Add SSH download function for SFTP file retrieval

Add download() to the ssh module, mirroring the existing upload()
function. Reads a remote file via SFTP and writes it to a local path,
creating parent directories as needed. Used by forge-builder to retrieve
build artifacts from builder VMs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Till Wegmueller 2026-02-15 17:17:38 +01:00
parent 4b29883247
commit 302f375f19
No known key found for this signature in database

View file

@ -204,6 +204,36 @@ pub fn upload(sess: &Session, local: &Path, remote: &Path) -> Result<()> {
Ok(())
}
/// Download a remote file to a local path via SFTP.
pub fn download(sess: &Session, remote: &Path, local: &Path) -> Result<()> {
let sftp = sess.sftp().map_err(|e| VmError::SshFailed {
detail: format!("SFTP init: {e}"),
})?;
let mut remote_file = sftp.open(remote).map_err(|e| VmError::SshFailed {
detail: format!("SFTP open {}: {e}", remote.display()),
})?;
let mut buf = Vec::new();
remote_file
.read_to_end(&mut buf)
.map_err(|e| VmError::SshFailed {
detail: format!("SFTP read {}: {e}", remote.display()),
})?;
if let Some(parent) = local.parent() {
std::fs::create_dir_all(parent).map_err(|e| VmError::SshFailed {
detail: format!("create local dir {}: {e}", parent.display()),
})?;
}
std::fs::write(local, &buf).map_err(|e| VmError::SshFailed {
detail: format!("write local file {}: {e}", local.display()),
})?;
Ok(())
}
/// Connect with exponential backoff retry.
///
/// Retries the connection until `timeout` elapses, with exponential backoff capped at 5 seconds.