1use 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 SubmoduleAction {
11 Add {
13 url: String,
15 path: Option<PathBuf>,
17 branch: Option<String>,
19 force: bool,
21 },
22 Init {
24 paths: Vec<PathBuf>,
26 },
27 Update {
29 init: bool,
31 recursive: bool,
33 remote: bool,
35 force: bool,
37 paths: Vec<PathBuf>,
39 },
40 Status {
42 cached: bool,
44 recursive: bool,
46 paths: Vec<PathBuf>,
48 },
49 Foreach {
51 command: String,
53 recursive: bool,
55 },
56 Deinit {
58 force: bool,
60 all: bool,
62 paths: Vec<PathBuf>,
64 },
65 Sync {
67 recursive: bool,
69 paths: Vec<PathBuf>,
71 },
72}
73
74#[derive(Debug, Clone)]
76pub struct SubmoduleCommand {
77 pub executor: CommandExecutor,
79 pub action: SubmoduleAction,
81}
82
83impl SubmoduleCommand {
84 pub fn add(url: impl Into<String>) -> Self {
86 Self {
87 executor: CommandExecutor::default(),
88 action: SubmoduleAction::Add {
89 url: url.into(),
90 path: None,
91 branch: None,
92 force: false,
93 },
94 }
95 }
96
97 pub fn path(&mut self, p: impl Into<PathBuf>) -> &mut Self {
99 if let SubmoduleAction::Add { path, .. } = &mut self.action {
100 *path = Some(p.into());
101 }
102 self
103 }
104
105 pub fn branch(&mut self, b: impl Into<String>) -> &mut Self {
107 if let SubmoduleAction::Add { branch, .. } = &mut self.action {
108 *branch = Some(b.into());
109 }
110 self
111 }
112
113 pub fn force(&mut self) -> &mut Self {
115 match &mut self.action {
116 SubmoduleAction::Add { force, .. }
117 | SubmoduleAction::Update { force, .. }
118 | SubmoduleAction::Deinit { force, .. } => {
119 *force = true;
120 }
121 _ => {}
122 }
123 self
124 }
125
126 #[must_use]
128 pub fn init() -> Self {
129 Self {
130 executor: CommandExecutor::default(),
131 action: SubmoduleAction::Init { paths: vec![] },
132 }
133 }
134
135 #[must_use]
137 pub fn update() -> Self {
138 Self {
139 executor: CommandExecutor::default(),
140 action: SubmoduleAction::Update {
141 init: false,
142 recursive: false,
143 remote: false,
144 force: false,
145 paths: vec![],
146 },
147 }
148 }
149
150 pub fn with_init(&mut self) -> &mut Self {
152 if let SubmoduleAction::Update { init, .. } = &mut self.action {
153 *init = true;
154 }
155 self
156 }
157
158 pub fn recursive(&mut self) -> &mut Self {
160 match &mut self.action {
161 SubmoduleAction::Update { recursive, .. }
162 | SubmoduleAction::Status { recursive, .. }
163 | SubmoduleAction::Foreach { recursive, .. }
164 | SubmoduleAction::Sync { recursive, .. } => {
165 *recursive = true;
166 }
167 _ => {}
168 }
169 self
170 }
171
172 pub fn remote(&mut self) -> &mut Self {
174 if let SubmoduleAction::Update { remote, .. } = &mut self.action {
175 *remote = true;
176 }
177 self
178 }
179
180 pub fn restrict_path(&mut self, p: impl Into<PathBuf>) -> &mut Self {
182 let p = p.into();
183 match &mut self.action {
184 SubmoduleAction::Init { paths }
185 | SubmoduleAction::Update { paths, .. }
186 | SubmoduleAction::Status { paths, .. }
187 | SubmoduleAction::Deinit { paths, .. }
188 | SubmoduleAction::Sync { paths, .. } => {
189 paths.push(p);
190 }
191 _ => {}
192 }
193 self
194 }
195
196 #[must_use]
198 pub fn status() -> Self {
199 Self {
200 executor: CommandExecutor::default(),
201 action: SubmoduleAction::Status {
202 cached: false,
203 recursive: false,
204 paths: vec![],
205 },
206 }
207 }
208
209 pub fn cached(&mut self) -> &mut Self {
211 if let SubmoduleAction::Status { cached, .. } = &mut self.action {
212 *cached = true;
213 }
214 self
215 }
216
217 pub fn foreach(command: impl Into<String>) -> Self {
219 Self {
220 executor: CommandExecutor::default(),
221 action: SubmoduleAction::Foreach {
222 command: command.into(),
223 recursive: false,
224 },
225 }
226 }
227
228 #[must_use]
230 pub fn deinit() -> Self {
231 Self {
232 executor: CommandExecutor::default(),
233 action: SubmoduleAction::Deinit {
234 force: false,
235 all: false,
236 paths: vec![],
237 },
238 }
239 }
240
241 pub fn all(&mut self) -> &mut Self {
243 if let SubmoduleAction::Deinit { all, .. } = &mut self.action {
244 *all = true;
245 }
246 self
247 }
248
249 #[must_use]
251 pub fn sync() -> Self {
252 Self {
253 executor: CommandExecutor::default(),
254 action: SubmoduleAction::Sync {
255 recursive: false,
256 paths: vec![],
257 },
258 }
259 }
260}
261
262#[async_trait]
263impl GitCommand for SubmoduleCommand {
264 type Output = CommandOutput;
265 fn get_executor(&self) -> &CommandExecutor {
266 &self.executor
267 }
268 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
269 &mut self.executor
270 }
271 fn build_command_args(&self) -> Vec<String> {
272 let mut args = vec!["submodule".to_string()];
273 match &self.action {
274 SubmoduleAction::Add {
275 url,
276 path,
277 branch,
278 force,
279 } => {
280 args.push("add".into());
281 if *force {
282 args.push("--force".into());
283 }
284 if let Some(b) = branch {
285 args.push("-b".into());
286 args.push(b.clone());
287 }
288 args.push(url.clone());
289 if let Some(p) = path {
290 args.push(p.display().to_string());
291 }
292 }
293 SubmoduleAction::Init { paths } => {
294 args.push("init".into());
295 if !paths.is_empty() {
296 args.push("--".into());
297 args.extend(paths.iter().map(|p| p.display().to_string()));
298 }
299 }
300 SubmoduleAction::Update {
301 init,
302 recursive,
303 remote,
304 force,
305 paths,
306 } => {
307 args.push("update".into());
308 if *init {
309 args.push("--init".into());
310 }
311 if *recursive {
312 args.push("--recursive".into());
313 }
314 if *remote {
315 args.push("--remote".into());
316 }
317 if *force {
318 args.push("--force".into());
319 }
320 if !paths.is_empty() {
321 args.push("--".into());
322 args.extend(paths.iter().map(|p| p.display().to_string()));
323 }
324 }
325 SubmoduleAction::Status {
326 cached,
327 recursive,
328 paths,
329 } => {
330 args.push("status".into());
331 if *cached {
332 args.push("--cached".into());
333 }
334 if *recursive {
335 args.push("--recursive".into());
336 }
337 if !paths.is_empty() {
338 args.push("--".into());
339 args.extend(paths.iter().map(|p| p.display().to_string()));
340 }
341 }
342 SubmoduleAction::Foreach { command, recursive } => {
343 args.push("foreach".into());
344 if *recursive {
345 args.push("--recursive".into());
346 }
347 args.push(command.clone());
348 }
349 SubmoduleAction::Deinit { force, all, paths } => {
350 args.push("deinit".into());
351 if *force {
352 args.push("--force".into());
353 }
354 if *all {
355 args.push("--all".into());
356 }
357 if !paths.is_empty() {
358 args.push("--".into());
359 args.extend(paths.iter().map(|p| p.display().to_string()));
360 }
361 }
362 SubmoduleAction::Sync { recursive, paths } => {
363 args.push("sync".into());
364 if *recursive {
365 args.push("--recursive".into());
366 }
367 if !paths.is_empty() {
368 args.push("--".into());
369 args.extend(paths.iter().map(|p| p.display().to_string()));
370 }
371 }
372 }
373 args
374 }
375 async fn execute(&self) -> Result<CommandOutput> {
376 self.execute_raw().await
377 }
378}