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 #[must_use]
58 pub fn bad_commit(mut self, c: impl Into<String>) -> Self {
59 if let BisectAction::Start { bad, .. } = &mut self.action {
60 *bad = Some(c.into());
61 }
62 self
63 }
64
65 #[must_use]
67 pub fn good_commit(mut self, c: impl Into<String>) -> Self {
68 if let BisectAction::Start { good, .. } = &mut self.action {
69 good.push(c.into());
70 }
71 self
72 }
73
74 #[must_use]
76 pub fn good(revs: Vec<String>) -> Self {
77 Self {
78 executor: CommandExecutor::default(),
79 action: BisectAction::Good(revs),
80 }
81 }
82
83 #[must_use]
85 pub fn bad(rev: Option<String>) -> Self {
86 Self {
87 executor: CommandExecutor::default(),
88 action: BisectAction::Bad(rev),
89 }
90 }
91
92 #[must_use]
94 pub fn skip(revs: Vec<String>) -> Self {
95 Self {
96 executor: CommandExecutor::default(),
97 action: BisectAction::Skip(revs),
98 }
99 }
100
101 #[must_use]
103 pub fn reset(commit: Option<String>) -> Self {
104 Self {
105 executor: CommandExecutor::default(),
106 action: BisectAction::Reset(commit),
107 }
108 }
109
110 #[must_use]
112 pub fn log() -> Self {
113 Self {
114 executor: CommandExecutor::default(),
115 action: BisectAction::Log,
116 }
117 }
118
119 pub fn replay(path: impl Into<PathBuf>) -> Self {
121 Self {
122 executor: CommandExecutor::default(),
123 action: BisectAction::Replay(path.into()),
124 }
125 }
126
127 pub fn run<I, S>(command: I) -> Self
129 where
130 I: IntoIterator<Item = S>,
131 S: Into<String>,
132 {
133 Self {
134 executor: CommandExecutor::default(),
135 action: BisectAction::Run(command.into_iter().map(Into::into).collect()),
136 }
137 }
138}
139
140#[async_trait]
141impl GitCommand for BisectCommand {
142 type Output = CommandOutput;
143 fn get_executor(&self) -> &CommandExecutor {
144 &self.executor
145 }
146 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
147 &mut self.executor
148 }
149 fn build_command_args(&self) -> Vec<String> {
150 let mut args = vec!["bisect".to_string()];
151 match &self.action {
152 BisectAction::Start { bad, good } => {
153 args.push("start".into());
154 if let Some(b) = bad {
155 args.push(b.clone());
156 }
157 args.extend(good.iter().cloned());
158 }
159 BisectAction::Good(revs) => {
160 args.push("good".into());
161 args.extend(revs.iter().cloned());
162 }
163 BisectAction::Bad(rev) => {
164 args.push("bad".into());
165 if let Some(r) = rev {
166 args.push(r.clone());
167 }
168 }
169 BisectAction::Skip(revs) => {
170 args.push("skip".into());
171 args.extend(revs.iter().cloned());
172 }
173 BisectAction::Reset(c) => {
174 args.push("reset".into());
175 if let Some(c) = c {
176 args.push(c.clone());
177 }
178 }
179 BisectAction::Log => args.push("log".into()),
180 BisectAction::Replay(p) => {
181 args.push("replay".into());
182 args.push(p.display().to_string());
183 }
184 BisectAction::Run(cmd) => {
185 args.push("run".into());
186 args.extend(cmd.iter().cloned());
187 }
188 }
189 args
190 }
191 async fn execute(&self) -> Result<CommandOutput> {
192 self.execute_raw().await
193 }
194}