src/commands
src/commands/update.rs
use std::{
io::{BufRead, BufReader, Read},
path::Path,
process::Stdio,
};
use crate::{RemoteOrLocalBuf, cli::UpdateCommand};
use jj_cli::{
cli_util::CommandHelper,
command_error::{CommandError, user_error},
ui::Ui,
};
pub mod hub;
pub mod repo;
pub async fn run(ui: &mut Ui, ch: &CommandHelper, cmd: &UpdateCommand) -> Result<(), CommandError> {
match cmd {
UpdateCommand::Hub => hub::run(ui, ch).await,
UpdateCommand::Repo => repo::run(ui, ch).await,
}
}
pub fn rsync(
ui: &mut Ui,
path: &Path,
output: &RemoteOrLocalBuf,
delete: Option<(&str, &[String])>,
) -> Result<(), CommandError> {
let mut child = std::process::Command::new("rsync")
.arg("-avzc")
.args(if let Some(delete) = delete {
let mut args = Vec::with_capacity(delete.1.len() + 2);
args.push("--delete".to_string());
for del in delete.1 {
args.push(format!("--filter=R /{}/{}/***", delete.0, del));
}
args.push("--filter=P /***".to_string());
args
} else {
vec![]
})
.arg(format!("{}/", path.display()))
.arg(output.to_string())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let stdout = child.stdout.take().unwrap();
let stderr = child.stderr.take().unwrap();
let stderr_handle = std::thread::spawn(move || {
let mut buf = Vec::new();
BufReader::new(stderr).read_to_end(&mut buf).ok();
buf
});
for line in BufReader::new(stdout).lines() {
let line = line?;
writeln!(ui.stdout_formatter(), "{line}")?;
}
let status = child.wait()?;
let stderr_buf = stderr_handle.join().unwrap_or_default();
if !stderr_buf.is_empty() {
write!(
ui.stderr_formatter(),
"{}",
String::from_utf8_lossy(&stderr_buf)
)?;
}
if !status.success() {
return Err(user_error("Couldn't rsync to the hub"));
}
Ok(())
}