Skip to main content

git_spawn/command/
update_ref.rs

1//! `git update-ref` — update the object name stored in a ref safely.
2
3use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::{Error, Result};
5use async_trait::async_trait;
6
7/// Builder for `git update-ref`.
8#[derive(Debug, Clone, Default)]
9pub struct UpdateRefCommand {
10    /// Shared executor.
11    pub executor: CommandExecutor,
12    /// Ref name (e.g. `"refs/heads/main"`).
13    pub ref_name: Option<String>,
14    /// New object.
15    pub new_value: Option<String>,
16    /// Expected old object (for safe update).
17    pub old_value: Option<String>,
18    /// `-d` delete mode.
19    pub delete: bool,
20    /// `--no-deref`.
21    pub no_deref: bool,
22    /// `-m <reason>`.
23    pub message: Option<String>,
24}
25
26impl UpdateRefCommand {
27    /// New command.
28    #[must_use]
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    /// Set ref name.
34    pub fn ref_name(&mut self, r: impl Into<String>) -> &mut Self {
35        self.ref_name = Some(r.into());
36        self
37    }
38
39    /// Set new value.
40    pub fn new_value(&mut self, v: impl Into<String>) -> &mut Self {
41        self.new_value = Some(v.into());
42        self
43    }
44
45    /// Set expected old value (compare-and-set).
46    pub fn old_value(&mut self, v: impl Into<String>) -> &mut Self {
47        self.old_value = Some(v.into());
48        self
49    }
50
51    /// Delete the ref.
52    pub fn delete(&mut self) -> &mut Self {
53        self.delete = true;
54        self
55    }
56
57    /// `--no-deref`.
58    pub fn no_deref(&mut self) -> &mut Self {
59        self.no_deref = true;
60        self
61    }
62
63    /// Reflog message.
64    pub fn message(&mut self, m: impl Into<String>) -> &mut Self {
65        self.message = Some(m.into());
66        self
67    }
68}
69
70#[async_trait]
71impl GitCommand for UpdateRefCommand {
72    type Output = CommandOutput;
73    fn get_executor(&self) -> &CommandExecutor {
74        &self.executor
75    }
76    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
77        &mut self.executor
78    }
79    fn build_command_args(&self) -> Vec<String> {
80        let mut args = vec!["update-ref".to_string()];
81        if self.no_deref {
82            args.push("--no-deref".into());
83        }
84        if let Some(m) = &self.message {
85            args.push("-m".into());
86            args.push(m.clone());
87        }
88        if self.delete {
89            args.push("-d".into());
90            if let Some(r) = &self.ref_name {
91                args.push(r.clone());
92            }
93            if let Some(o) = &self.old_value {
94                args.push(o.clone());
95            }
96            return args;
97        }
98        if let Some(r) = &self.ref_name {
99            args.push(r.clone());
100        }
101        if let Some(v) = &self.new_value {
102            args.push(v.clone());
103        }
104        if let Some(o) = &self.old_value {
105            args.push(o.clone());
106        }
107        args
108    }
109    async fn execute(&self) -> Result<CommandOutput> {
110        if self.ref_name.is_none() {
111            return Err(Error::invalid_config("update-ref requires a ref name"));
112        }
113        if !self.delete && self.new_value.is_none() {
114            return Err(Error::invalid_config(
115                "update-ref requires a new value unless --delete is set",
116            ));
117        }
118        self.execute_raw().await
119    }
120}