use std::path::Path; use anyhow::Context; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonEditOptions { pub jq: String, } impl JsonEditOptions { pub fn execute(&self, path: &Path, next_version: impl AsRef) -> anyhow::Result<()> { let next_version = next_version.as_ref(); let jq_query = self.jq.replace("%%version%%", next_version); if !path.exists() { anyhow::bail!("could not find file at: {}", path.display()); } if let Ok(metadata) = path.metadata() { if !metadata.is_file() { anyhow::bail!("{} is not a file", path.display()); } } let abs_path = path.canonicalize().context(anyhow::anyhow!( "could not get absolute path from {}", path.display() ))?; let output = std::process::Command::new("jq") .arg(format!("{}", jq_query)) .arg( abs_path .to_str() .ok_or(anyhow::anyhow!("path contains non utf-8 chars"))?, ) .output() .context(anyhow::anyhow!( "failed to run jq on file, jq may not be installed or query was invalid" ))?; if !output.status.success() { let err_content = std::str::from_utf8(output.stderr.as_slice())?; anyhow::bail!("failed to run jq with output: {}", err_content); } let edited_json_content = std::str::from_utf8(output.stdout.as_slice())?; tracing::trace!( new_content = edited_json_content, file = &abs_path.display().to_string(), "applied jq to file" ); std::fs::write(abs_path, edited_json_content)?; Ok(()) } }