elvsc

19 commits
Updated 2026-04-30 16:50:05
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(())
}