use std::path::{Path, PathBuf};
use std::process::Output;
use std::time::{Duration, Instant};
use tokio::process::Command;
use crate::logging::{log_debug, log_error, log_info, log_process_output, log_timed};
pub async fn run_redeploy() -> Result<(), String> {
let current_dir: PathBuf =
std::env::current_dir().map_err(|e| format!("Failed to get current directory: {}", e))?;
let mut dir: &Path = current_dir.as_path();
let mut xbp_path: Option<PathBuf> = None;
let mut working_dir: Option<PathBuf> = None;
for _ in 0..2 {
let potential_path: PathBuf = dir.join(".xbp").join("redeploy.sh");
log_debug(
"redeploy",
&format!("Checking for redeploy.sh at: {}", potential_path.display()),
None,
)
.await
.ok();
if potential_path.exists() {
xbp_path = Some(potential_path);
working_dir = Some(dir.to_path_buf());
log_debug(
"redeploy",
&format!(
"Found redeploy.sh at: {}",
xbp_path.as_ref().unwrap().display()
),
None,
)
.await
.ok();
log_debug(
"redeploy",
&format!(
"Will execute from working directory: {}",
working_dir.as_ref().unwrap().display()
),
None,
)
.await
.ok();
break;
}
if let Some(parent) = dir.parent() {
dir = parent;
} else {
break;
}
}
if let Some(xbp_path) = xbp_path {
let working_dir = working_dir.expect("working_dir should be set when xbp_path is found");
log_info(
"redeploy",
&format!("Found redeploy.sh at: {}", xbp_path.display()),
None,
)
.await
.ok();
let chmod_start: Instant = Instant::now();
let chmod_output: Output = match Command::new("sudo")
.arg("chmod")
.arg("+x")
.arg(&xbp_path)
.output()
.await
{
Ok(output) => output,
Err(e) => {
let error_msg = format!("Failed to execute chmod command: {}", e);
log_error("redeploy", &error_msg, None).await.ok();
return Err(error_msg);
}
};
let chmod_elapsed: Duration = chmod_start.elapsed();
log_info("redeploy", "Made redeploy.sh executable.", None)
.await
.ok();
log_debug(
"redeploy",
&format!("chmod output: {:?}", chmod_output),
None,
)
.await
.ok();
log_timed(
crate::logging::LogLevel::Debug,
"redeploy",
"chmod",
chmod_elapsed.as_millis() as u64,
)
.await
.ok();
if !chmod_output.status.success() {
let error_msg = format!(
"Failed to make redeploy.sh executable: {}",
String::from_utf8_lossy(&chmod_output.stderr)
);
log_error("redeploy", &error_msg, None).await.ok();
return Err(error_msg);
}
let redeploy_start: Instant = Instant::now();
let redeploy_output: Output = Command::new(&xbp_path)
.current_dir(&working_dir)
.output()
.await
.map_err(|e| format!("Failed to execute redeploy.sh: {}", e))?;
let redeploy_elapsed = redeploy_start.elapsed();
log_debug(
"redeploy",
&format!("redeploy.sh output: {:?}", redeploy_output),
None,
)
.await
.ok();
log_timed(
crate::logging::LogLevel::Debug,
"redeploy",
"redeploy.sh",
redeploy_elapsed.as_millis() as u64,
)
.await
.ok();
let stdout_output = String::from_utf8_lossy(&redeploy_output.stdout);
let stderr_output = String::from_utf8_lossy(&redeploy_output.stderr);
if !redeploy_output.status.success() {
if stderr_output.contains("./xbp.json not found")
|| stdout_output.contains("./xbp.json not found")
{
let xbp_json_path = working_dir.join("xbp.json");
let error_msg = if xbp_json_path.exists() {
format!(
"Failed to run redeploy.sh: xbp.json not found in working directory.\n\
Script was executed from: {}\n\
Expected xbp.json at: {}\n\
Note: The script looks for ./xbp.json relative to its execution directory.\n\
stderr: {}\nstdout: {}",
working_dir.display(),
xbp_json_path.display(),
stderr_output,
stdout_output
)
} else {
format!(
"Failed to run redeploy.sh: xbp.json not found.\n\
Script was executed from: {}\n\
Expected xbp.json at: {}\n\
Please ensure xbp.json exists in the project root.\n\
stderr: {}\nstdout: {}",
working_dir.display(),
xbp_json_path.display(),
stderr_output,
stdout_output
)
};
log_error("redeploy", &error_msg, None).await.ok();
let _ =
log_process_output("redeploy", "redeploy.sh", &stdout_output, &stderr_output)
.await;
return Err(error_msg);
}
let error_msg = format!(
"Failed to run redeploy.sh:\nstderr: {}\nstdout: {}",
stderr_output, stdout_output
);
log_error("redeploy", &error_msg, None).await.ok();
let _ =
log_process_output("redeploy", "redeploy.sh", &stdout_output, &stderr_output).await;
return Err(error_msg);
}
log_info(
"redeploy",
&format!("Redeploy output: {}", stdout_output),
None,
)
.await
.ok();
let _ = log_process_output("redeploy", "redeploy.sh", &stdout_output, &stderr_output).await;
Ok(())
} else {
let error_msg = "No .xbp/redeploy.sh found in the directory hierarchy.";
log_error("redeploy", error_msg, None).await.ok();
Err(error_msg.to_string())
}
}