git_spawn/command/
bisect.rs1use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6use std::path::PathBuf;
7
8#[derive(Debug, Clone)]
10pub enum BisectAction {
11 Start {
13 bad: Option<String>,
15 good: Vec<String>,
17 },
18 Good(Vec<String>),
20 Bad(Option<String>),
22 Skip(Vec<String>),
24 Reset(Option<String>),
26 Log,
28 Replay(PathBuf),
30 Run(Vec<String>),
32}
33
34#[derive(Debug, Clone)]
36pub struct BisectCommand {
37 pub executor: CommandExecutor,
39 pub action: BisectAction,
41}
42
43impl BisectCommand {
44 #[must_use]
46 pub fn start() -> Self {
47 Self {
48 executor: CommandExecutor::default(),
49 action: BisectAction::Start {
50 bad: None,
51 good: vec![],
52 },
53 }
54 }
55
56 pub fn bad_commit(&mut self, c: impl Into<String>) -> &mut Self {
58 if let BisectAction::Start { bad, .. } = &mut self.action {
59 *bad = Some(c.into());
60 }
61 self
62 }
63
64 pub fn good_commit(&mut self, c: impl Into<String>) -> &mut Self {
66 if let BisectAction::Start { good, .. } = &mut self.action {
67 good.push(c.into());
68 }
69 self
70 }
71
72 #[must_use]
74 pub fn good(revs: Vec<String>) -> Self {
75 Self {
76 executor: CommandExecutor::default(),
77 action: BisectAction::Good(revs),
78 }
79 }
80
81 #[must_use]
83 pub fn bad(rev: Option<String>) -> Self {
84 Self {
85 executor: CommandExecutor::default(),
86 action: BisectAction::Bad(rev),
87 }
88 }
89
90 #[must_use]
92 pub fn skip(revs: Vec<String>) -> Self {
93 Self {
94 executor: CommandExecutor::default(),
95 action: BisectAction::Skip(revs),
96 }
97 }
98
99 #[must_use]
101 pub fn reset(commit: Option<String>) -> Self {
102 Self {
103 executor: CommandExecutor::default(),
104 action: BisectAction::Reset(commit),
105 }
106 }
107
108 #[must_use]
110 pub fn log() -> Self {
111 Self {
112 executor: CommandExecutor::default(),
113 action: BisectAction::Log,
114 }
115 }
116
117 pub fn replay(path: impl Into<PathBuf>) -> Self {
119 Self {
120 executor: CommandExecutor::default(),
121 action: BisectAction::Replay(path.into()),
122 }
123 }
124
125 pub fn run<I, S>(command: I) -> Self
127 where
128 I: IntoIterator<Item = S>,
129 S: Into<String>,
130 {
131 Self {
132 executor: CommandExecutor::default(),
133 action: BisectAction::Run(command.into_iter().map(Into::into).collect()),
134 }
135 }
136}
137
138#[async_trait]
139impl GitCommand for BisectCommand {
140 type Output = CommandOutput;
141 fn get_executor(&self) -> &CommandExecutor {
142 &self.executor
143 }
144 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
145 &mut self.executor
146 }
147 fn build_command_args(&self) -> Vec<String> {
148 let mut args = vec!["bisect".to_string()];
149 match &self.action {
150 BisectAction::Start { bad, good } => {
151 args.push("start".into());
152 if let Some(b) = bad {
153 args.push(b.clone());
154 }
155 args.extend(good.iter().cloned());
156 }
157 BisectAction::Good(revs) => {
158 args.push("good".into());
159 args.extend(revs.iter().cloned());
160 }
161 BisectAction::Bad(rev) => {
162 args.push("bad".into());
163 if let Some(r) = rev {
164 args.push(r.clone());
165 }
166 }
167 BisectAction::Skip(revs) => {
168 args.push("skip".into());
169 args.extend(revs.iter().cloned());
170 }
171 BisectAction::Reset(c) => {
172 args.push("reset".into());
173 if let Some(c) = c {
174 args.push(c.clone());
175 }
176 }
177 BisectAction::Log => args.push("log".into()),
178 BisectAction::Replay(p) => {
179 args.push("replay".into());
180 args.push(p.display().to_string());
181 }
182 BisectAction::Run(cmd) => {
183 args.push("run".into());
184 args.extend(cmd.iter().cloned());
185 }
186 }
187 args
188 }
189 async fn execute(&self) -> Result<CommandOutput> {
190 self.execute_raw().await
191 }
192}