exp: cross #2

This commit is contained in:
2025-12-20 00:06:07 +01:00
parent 8e9e19a6ca
commit 31bcd28c72
16 changed files with 1209 additions and 438 deletions

View File

@@ -2,7 +2,9 @@
/// Context driver: Copies over SFTP with ssh2, executes commands over ssh2 channels
use super::api::ContextDriver;
use log::debug;
use ssh2;
use std::fs;
use std::io::Write;
use std::io::{self, Read};
use std::net::TcpStream;
#[cfg(unix)]
@@ -90,7 +92,13 @@ impl ContextDriver for SshDriver {
Ok(files)
}
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus> {
fn run(
&self,
program: &str,
args: &[String],
env: &[(String, String)],
cwd: Option<&str>,
) -> io::Result<std::process::ExitStatus> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let mut channel = sess.channel_session().map_err(io::Error::other)?;
@@ -98,7 +106,14 @@ impl ContextDriver for SshDriver {
// TODO: No, use ssh2 channel.set_env
let mut cmd_line = String::new();
for (key, value) in env {
cmd_line.push_str(&format!("export {}='{}'; ", key, value.replace("'", "'\\''")));
cmd_line.push_str(&format!(
"export {}='{}'; ",
key,
value.replace("'", "'\\''")
));
}
if let Some(dir) = cwd {
cmd_line.push_str(&format!("cd {} && ", dir));
}
cmd_line.push_str(program);
for arg in args {
@@ -124,14 +139,27 @@ impl ContextDriver for SshDriver {
Ok(ExitStatus::from_raw(code))
}
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output> {
fn run_output(
&self,
program: &str,
args: &[String],
env: &[(String, String)],
cwd: Option<&str>,
) -> io::Result<std::process::Output> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let mut channel = sess.channel_session().map_err(io::Error::other)?;
// Construct command line with env vars
let mut cmd_line = String::new();
for (key, value) in env {
cmd_line.push_str(&format!("export {}='{}'; ", key, value.replace("'", "'\\''")));
cmd_line.push_str(&format!(
"export {}='{}'; ",
key,
value.replace("'", "'\\''")
));
}
if let Some(dir) = cwd {
cmd_line.push_str(&format!("cd {} && ", dir));
}
cmd_line.push_str(program);
for arg in args {
@@ -164,7 +192,7 @@ impl ContextDriver for SshDriver {
})
}
fn prepare_work_dir(&self) -> io::Result<String> {
fn create_temp_dir(&self) -> io::Result<String> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let mut channel = sess.channel_session().map_err(io::Error::other)?;
@@ -182,6 +210,40 @@ impl ContextDriver for SshDriver {
Ok(stdout.trim().to_string())
}
fn copy_path(&self, src: &Path, dest: &Path) -> io::Result<()> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let mut channel = sess.channel_session().map_err(io::Error::other)?;
// TODO: use sftp
let cmd = format!("cp -a {:?} {:?}", src, dest);
debug!("Executing remote copy: {}", cmd);
channel.exec(&cmd).map_err(io::Error::other)?;
channel.wait_close().map_err(io::Error::other)?;
if channel.exit_status().unwrap_or(-1) != 0 {
return Err(io::Error::other(format!("Remote copy failed: {}", cmd)));
}
Ok(())
}
fn read_file(&self, path: &Path) -> io::Result<String> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let sftp = sess.sftp().map_err(io::Error::other)?;
let mut remote_file = sftp.open(path).map_err(io::Error::other)?;
let mut content = String::new();
remote_file.read_to_string(&mut content)?;
Ok(content)
}
fn write_file(&self, path: &Path, content: &str) -> io::Result<()> {
let sess = connect_ssh(&self.host, self.user.as_deref(), self.port)?;
let sftp = sess.sftp().map_err(io::Error::other)?;
if let Some(parent) = path.parent() {
let _ = sftp.mkdir(parent, 0o755);
}
let mut remote_file = sftp.create(path).map_err(io::Error::other)?;
remote_file.write_all(content.as_bytes())?;
Ok(())
}
}
impl SshDriver {