use anyhow::bail;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use uuid::Uuid;
use crate::utils::is_verbose;
fn run(cmd: impl AsRef<str>, files: &[&str], working_dir: &Path) -> anyhow::Result<()> {
if !std::process::Command::new(cmd.as_ref())
.args(files)
.current_dir(working_dir)
.status()?
.success()
{
bail!("`{}` wasn't executed successfully!", cmd.as_ref())
}
Ok(())
}
#[derive(Deserialize, Serialize)]
struct FindByRequest {
content: String,
start_pos: Option<usize>,
end_pos: Option<usize>,
}
#[derive(Deserialize, Serialize)]
struct FindByResponse {
start_pos: Option<usize>,
end_pos: Option<usize>,
cursor_at_end: bool,
}
pub fn find_by(
patch_dir: &Path,
path: &Path,
content: &str,
start_pos: Option<usize>,
end_pos: Option<usize>,
) -> anyhow::Result<(Option<usize>, Option<usize>, bool)> {
let patch_path = patch_dir.to_path_buf().join(path);
if !patch_path.is_file() {
bail!("Shell script path ({:?}) has to be a file.", patch_path)
}
if is_verbose() { println!(">>> Find by sh: patch_path = {patch_path:?}"); }
let req_filename = format!("find_by.req.{}.json", Uuid::new_v4().as_simple());
let res_filename = format!("find_by.res.{}.json", Uuid::new_v4().as_simple());
let req_path = patch_dir.join(&req_filename);
let res_path = patch_dir.join(&res_filename);
if is_verbose() {
println!(">>> Find by sh: req_path = {req_path:?}");
println!(">>> Find by sh: res_path = {res_path:?}");
}
let request = FindByRequest {
content: content.to_string(),
start_pos,
end_pos,
};
let request = serde_json::to_string(&request)?;
std::fs::write(&req_path, request)?;
let script_filename = path.to_string_lossy().to_string();
let result = run(
script_filename,
&[req_filename.as_str(), res_filename.as_str()],
patch_dir,
);
if is_verbose() { println!(">>> Shell script completed (for `find_by` request): {path:?}"); }
let response = std::fs::read_to_string(&res_path)?;
let response = serde_json::from_str::<FindByResponse>(&response)?;
let _ = std::fs::remove_file(&req_path);
let _ = std::fs::remove_file(&res_path);
result?;
Ok((response.start_pos, response.end_pos, response.cursor_at_end))
}
#[derive(Deserialize, Serialize)]
struct ReplaceByRequest {
content: String,
}
#[derive(Deserialize, Serialize)]
struct ReplaceByResponse {
content: String,
}
pub fn replace_by(patch_dir: &Path, path: &Path, content: &str) -> anyhow::Result<String> {
let patch_path = patch_dir.to_path_buf().join(path);
if !patch_path.is_file() {
bail!("Shell script path ({:?}) has to be a file.", patch_path)
}
if is_verbose() { println!(">>> Replace by sh: patch_path = {patch_path:?}"); }
let req_filename = format!("replace.req.{}.json", Uuid::new_v4().as_simple());
let res_filename = format!("replace.res.{}.json", Uuid::new_v4().as_simple());
let req_path = patch_dir.join(&req_filename);
let res_path = patch_dir.join(&res_filename);
if is_verbose() {
println!(">>> Replace by sh: req_path = {req_path:?}");
println!(">>> Replace by sh: res_path = {res_path:?}");
}
let request = ReplaceByRequest {
content: content.to_string(),
};
let request = serde_json::to_string(&request)?;
std::fs::write(&req_path, request)?;
let script_filename = path.to_string_lossy().to_string();
let result = run(
script_filename,
&[req_filename.as_str(), res_filename.as_str()],
patch_dir,
);
if is_verbose() { println!(">>> Shell script completed (for `replace_by` request): {path:?}"); }
let response = std::fs::read_to_string(&res_path)?;
let response = serde_json::from_str::<ReplaceByResponse>(&response)?;
let _ = std::fs::remove_file(&req_path);
let _ = std::fs::remove_file(&res_path);
result?;
Ok(response.content)
}
#[derive(Deserialize, Serialize)]
struct DecodeByRequest {
encoded_file: PathBuf,
}
#[derive(Deserialize, Serialize)]
struct DecodeByResponse {
content: String,
}
pub fn decode_by(patch_dir: &Path, path: &Path, encoded_filepath: PathBuf) -> anyhow::Result<String> {
let patch_path = patch_dir.to_path_buf().join(path);
if !patch_path.is_file() {
bail!("Shell script path ({:?}) has to be a file.", patch_path)
}
if is_verbose() { println!(">>> Decode by sh: patch_path = {patch_path:?}"); }
let req_filename = format!("decode.req.{}.json", Uuid::new_v4().as_simple());
let res_filename = format!("decode.res.{}.json", Uuid::new_v4().as_simple());
let req_path = patch_dir.join(&req_filename);
let res_path = patch_dir.join(&res_filename);
if is_verbose() {
println!(">>> Decode by sh: req_path = {req_path:?}");
println!(">>> Decode by sh: res_path = {res_path:?}");
}
let request = DecodeByRequest {
encoded_file: encoded_filepath,
};
let request = serde_json::to_string(&request)?;
std::fs::write(&req_path, request)?;
let script_filename = path.to_string_lossy().to_string();
let result = run(
script_filename,
&[req_filename.as_str(), res_filename.as_str()],
patch_dir,
);
if is_verbose() { println!(">>> Shell script completed (for `decode_by` request): {path:?}"); }
let response = std::fs::read_to_string(&res_path)?;
let response = serde_json::from_str::<DecodeByResponse>(&response)?;
let _ = std::fs::remove_file(&req_path);
let _ = std::fs::remove_file(&res_path);
result?;
Ok(response.content)
}
#[derive(Deserialize, Serialize)]
struct EncodeByRequest {
write_to_file: PathBuf,
content: String,
}
pub fn encode_by(patch_dir: &Path, path: &Path, content: &str, write_to_filepath: PathBuf) -> anyhow::Result<()> {
let patch_path = patch_dir.to_path_buf().join(path);
if !patch_path.is_file() {
bail!("Shell script path ({:?}) has to be a file.", patch_path)
}
if is_verbose() { println!(">>> Encode by sh: patch_path = {patch_path:?}"); }
let req_filename = format!("encode.req.{}.json", Uuid::new_v4().as_simple());
let req_path = patch_dir.join(&req_filename);
if is_verbose() {
println!(">>> Encode by sh: req_path = {req_path:?}");
}
let request = EncodeByRequest {
write_to_file: write_to_filepath,
content: content.to_string(),
};
let request = serde_json::to_string(&request)?;
std::fs::write(&req_path, request)?;
let script_filename = path.to_string_lossy().to_string();
let result = run(script_filename, &[req_filename.as_str()], patch_dir);
if is_verbose() { println!(">>> Shell script completed (for `encode_by` request): {path:?}"); }
let _ = std::fs::remove_file(&req_path);
result?;
Ok(())
}