Skip to main content

mkit_cli/commands/
pull.rs

1//! `mkit pull [<remote>]` — fetch refs from the configured remote
2//! (named, or the flat default) and fast-forward the current branch.
3
4use std::io::Write;
5
6use clap::Parser;
7
8use crate::clap_shim;
9use crate::config;
10use crate::exit;
11use crate::remote_dispatch;
12
13#[derive(Debug, Parser)]
14#[command(name = "mkit pull", about = "Pull changes from the configured remote.")]
15struct PullOpts {
16    /// Named remote to pull from (default: the flat default remote).
17    remote: Option<String>,
18}
19
20#[must_use]
21pub fn run(args: &[String]) -> u8 {
22    let opts = match clap_shim::parse::<PullOpts>("mkit pull", args) {
23        Ok(o) => o,
24        Err(code) => return code,
25    };
26    let cwd = match std::env::current_dir() {
27        Ok(p) => p,
28        Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
29    };
30    let cfg = match config::read_layered(&cwd) {
31        Ok(c) => c,
32        Err(e) => return emit_err(&format!("config: {e}"), exit::CONFIG_ERROR),
33    };
34    let Some(resolved) = config::resolve_remote(&cfg, opts.remote.as_deref().unwrap_or("")) else {
35        return emit_err(
36            &match opts.remote.as_deref() {
37                Some(name) => format!("unknown remote '{name}'"),
38                None => "no remote configured — use `mkit remote add <url>`".to_owned(),
39            },
40            exit::CONFIG_ERROR,
41        );
42    };
43    let endpoint = resolved.endpoint.as_str();
44    match remote_dispatch::open_trusted(endpoint, resolved.repo_chosen, &cfg) {
45        Ok(tx) => match remote_dispatch::pull_all(&cwd, tx.as_ref(), &resolved.name) {
46            Ok(n) => {
47                let mut stderr = std::io::stderr().lock();
48                let _ = writeln!(stderr, "pulled {n} ref(s) from {endpoint}");
49                exit::OK
50            }
51            Err(remote_dispatch::DispatchError::Interrupted) => {
52                emit_err("pull: interrupted", exit::TEMPFAIL)
53            }
54            Err(e) => emit_err(&format!("pull: {e}"), exit::GENERAL_ERROR),
55        },
56        Err(remote_dispatch::DispatchError::UntrustedRemote(msg)) => {
57            emit_err(&msg, exit::CONFIG_ERROR)
58        }
59        Err(e) => emit_err(&format!("open remote: {e}"), exit::PROTOCOL_ERROR),
60    }
61}
62
63fn emit_err(msg: &str, code: u8) -> u8 {
64    let mut stderr = std::io::stderr().lock();
65    let _ = writeln!(stderr, "error: {msg}");
66    code
67}