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 #[must_use]
99 pub fn path(mut self, p: impl Into<PathBuf>) -> Self {
100 if let SubmoduleAction::Add { path, .. } = &mut self.action {
101 *path = Some(p.into());
102 }
103 self
104 }
105
106 #[must_use]
108 pub fn branch(mut self, b: impl Into<String>) -> Self {
109 if let SubmoduleAction::Add { branch, .. } = &mut self.action {
110 *branch = Some(b.into());
111 }
112 self
113 }
114
115 #[must_use]
117 pub fn force(mut self) -> Self {
118 match &mut self.action {
119 SubmoduleAction::Add { force, .. }
120 | SubmoduleAction::Update { force, .. }
121 | SubmoduleAction::Deinit { force, .. } => {
122 *force = true;
123 }
124 _ => {}
125 }
126 self
127 }
128
129 #[must_use]
131 pub fn init() -> Self {
132 Self {
133 executor: CommandExecutor::default(),
134 action: SubmoduleAction::Init { paths: vec![] },
135 }
136 }
137
138 #[must_use]
140 pub fn update() -> Self {
141 Self {
142 executor: CommandExecutor::default(),
143 action: SubmoduleAction::Update {
144 init: false,
145 recursive: false,
146 remote: false,
147 force: false,
148 paths: vec![],
149 },
150 }
151 }
152
153 #[must_use]
155 pub fn with_init(mut self) -> Self {
156 if let SubmoduleAction::Update { init, .. } = &mut self.action {
157 *init = true;
158 }
159 self
160 }
161
162 #[must_use]
164 pub fn recursive(mut self) -> Self {
165 match &mut self.action {
166 SubmoduleAction::Update { recursive, .. }
167 | SubmoduleAction::Status { recursive, .. }
168 | SubmoduleAction::Foreach { recursive, .. }
169 | SubmoduleAction::Sync { recursive, .. } => {
170 *recursive = true;
171 }
172 _ => {}
173 }
174 self
175 }
176
177 #[must_use]
179 pub fn remote(mut self) -> Self {
180 if let SubmoduleAction::Update { remote, .. } = &mut self.action {
181 *remote = true;
182 }
183 self
184 }
185
186 #[must_use]
188 pub fn restrict_path(mut self, p: impl Into<PathBuf>) -> Self {
189 let p = p.into();
190 match &mut self.action {
191 SubmoduleAction::Init { paths }
192 | SubmoduleAction::Update { paths, .. }
193 | SubmoduleAction::Status { paths, .. }
194 | SubmoduleAction::Deinit { paths, .. }
195 | SubmoduleAction::Sync { paths, .. } => {
196 paths.push(p);
197 }
198 _ => {}
199 }
200 self
201 }
202
203 #[must_use]
205 pub fn status() -> Self {
206 Self {
207 executor: CommandExecutor::default(),
208 action: SubmoduleAction::Status {
209 cached: false,
210 recursive: false,
211 paths: vec![],
212 },
213 }
214 }
215
216 #[must_use]
218 pub fn cached(mut self) -> Self {
219 if let SubmoduleAction::Status { cached, .. } = &mut self.action {
220 *cached = true;
221 }
222 self
223 }
224
225 pub fn foreach(command: impl Into<String>) -> Self {
227 Self {
228 executor: CommandExecutor::default(),
229 action: SubmoduleAction::Foreach {
230 command: command.into(),
231 recursive: false,
232 },
233 }
234 }
235
236 #[must_use]
238 pub fn deinit() -> Self {
239 Self {
240 executor: CommandExecutor::default(),
241 action: SubmoduleAction::Deinit {
242 force: false,
243 all: false,
244 paths: vec![],
245 },
246 }
247 }
248
249 #[must_use]
251 pub fn all(mut self) -> Self {
252 if let SubmoduleAction::Deinit { all, .. } = &mut self.action {
253 *all = true;
254 }
255 self
256 }
257
258 #[must_use]
260 pub fn sync() -> Self {
261 Self {
262 executor: CommandExecutor::default(),
263 action: SubmoduleAction::Sync {
264 recursive: false,
265 paths: vec![],
266 },
267 }
268 }
269}
270
271#[async_trait]
272impl GitCommand for SubmoduleCommand {
273 type Output = CommandOutput;
274 fn get_executor(&self) -> &CommandExecutor {
275 &self.executor
276 }
277 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
278 &mut self.executor
279 }
280 fn build_command_args(&self) -> Vec<String> {
281 let mut args = vec!["submodule".to_string()];
282 match &self.action {
283 SubmoduleAction::Add {
284 url,
285 path,
286 branch,
287 force,
288 } => {
289 args.push("add".into());
290 if *force {
291 args.push("--force".into());
292 }
293 if let Some(b) = branch {
294 args.push("-b".into());
295 args.push(b.clone());
296 }
297 args.push(url.clone());
298 if let Some(p) = path {
299 args.push(p.display().to_string());
300 }
301 }
302 SubmoduleAction::Init { paths } => {
303 args.push("init".into());
304 if !paths.is_empty() {
305 args.push("--".into());
306 args.extend(paths.iter().map(|p| p.display().to_string()));
307 }
308 }
309 SubmoduleAction::Update {
310 init,
311 recursive,
312 remote,
313 force,
314 paths,
315 } => {
316 args.push("update".into());
317 if *init {
318 args.push("--init".into());
319 }
320 if *recursive {
321 args.push("--recursive".into());
322 }
323 if *remote {
324 args.push("--remote".into());
325 }
326 if *force {
327 args.push("--force".into());
328 }
329 if !paths.is_empty() {
330 args.push("--".into());
331 args.extend(paths.iter().map(|p| p.display().to_string()));
332 }
333 }
334 SubmoduleAction::Status {
335 cached,
336 recursive,
337 paths,
338 } => {
339 args.push("status".into());
340 if *cached {
341 args.push("--cached".into());
342 }
343 if *recursive {
344 args.push("--recursive".into());
345 }
346 if !paths.is_empty() {
347 args.push("--".into());
348 args.extend(paths.iter().map(|p| p.display().to_string()));
349 }
350 }
351 SubmoduleAction::Foreach { command, recursive } => {
352 args.push("foreach".into());
353 if *recursive {
354 args.push("--recursive".into());
355 }
356 args.push(command.clone());
357 }
358 SubmoduleAction::Deinit { force, all, paths } => {
359 args.push("deinit".into());
360 if *force {
361 args.push("--force".into());
362 }
363 if *all {
364 args.push("--all".into());
365 }
366 if !paths.is_empty() {
367 args.push("--".into());
368 args.extend(paths.iter().map(|p| p.display().to_string()));
369 }
370 }
371 SubmoduleAction::Sync { recursive, paths } => {
372 args.push("sync".into());
373 if *recursive {
374 args.push("--recursive".into());
375 }
376 if !paths.is_empty() {
377 args.push("--".into());
378 args.extend(paths.iter().map(|p| p.display().to_string()));
379 }
380 }
381 }
382 args
383 }
384 async fn execute(&self) -> Result<CommandOutput> {
385 self.execute_raw().await
386 }
387}