34 use hg::StatusOptions; |
34 use hg::StatusOptions; |
35 use hg::{self, narrow, sparse}; |
35 use hg::{self, narrow, sparse}; |
36 use log::info; |
36 use log::info; |
37 use rayon::prelude::*; |
37 use rayon::prelude::*; |
38 use std::io; |
38 use std::io; |
|
39 use std::mem::take; |
39 use std::path::PathBuf; |
40 use std::path::PathBuf; |
40 |
41 |
41 pub const HELP_TEXT: &str = " |
42 pub const HELP_TEXT: &str = " |
42 Show changed files in the working directory |
43 Show changed files in the working directory |
43 |
44 |
283 }; |
284 }; |
284 |
285 |
285 type StatusResult<'a> = |
286 type StatusResult<'a> = |
286 Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>; |
287 Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>; |
287 |
288 |
|
289 let relative_status = config |
|
290 .get_option(b"commands", b"status.relative")? |
|
291 .expect("commands.status.relative should have a default value"); |
|
292 |
|
293 let relativize_paths = relative_status || { |
|
294 // See in Python code with `getuipathfn` usage in `commands.py`. |
|
295 let legacy_relative_behavior = args.contains_id("file"); |
|
296 match relative_paths(invocation.config)? { |
|
297 RelativePaths::Legacy => legacy_relative_behavior, |
|
298 RelativePaths::Bool(v) => v, |
|
299 } |
|
300 }; |
|
301 |
|
302 let mut output = DisplayStatusPaths { |
|
303 ui, |
|
304 no_status, |
|
305 relativize: if relativize_paths { |
|
306 Some(RelativizePaths::new(repo)?) |
|
307 } else { |
|
308 None |
|
309 }, |
|
310 print0, |
|
311 }; |
|
312 |
288 let after_status = |res: StatusResult| -> Result<_, CommandError> { |
313 let after_status = |res: StatusResult| -> Result<_, CommandError> { |
289 let (mut ds_status, pattern_warnings) = res?; |
314 let (mut ds_status, pattern_warnings) = res?; |
290 for warning in pattern_warnings { |
315 for warning in pattern_warnings { |
291 ui.write_stderr(&format_pattern_file_warning(&warning, repo))?; |
316 ui.write_stderr(&format_pattern_file_warning(&warning, repo))?; |
292 } |
317 } |
293 |
318 |
294 for (path, error) in ds_status.bad { |
319 for (path, error) in take(&mut ds_status.bad) { |
295 let error = match error { |
320 let error = match error { |
296 hg::BadMatch::OsError(code) => { |
321 hg::BadMatch::OsError(code) => { |
297 std::io::Error::from_raw_os_error(code).to_string() |
322 std::io::Error::from_raw_os_error(code).to_string() |
298 } |
323 } |
299 hg::BadMatch::BadType(ty) => { |
324 hg::BadMatch::BadType(ty) => { |
320 let manifest = repo.manifest_for_node(p1).map_err(|e| { |
345 let manifest = repo.manifest_for_node(p1).map_err(|e| { |
321 CommandError::from((e, &*format!("{:x}", p1.short()))) |
346 CommandError::from((e, &*format!("{:x}", p1.short()))) |
322 })?; |
347 })?; |
323 let working_directory_vfs = repo.working_directory_vfs(); |
348 let working_directory_vfs = repo.working_directory_vfs(); |
324 let store_vfs = repo.store_vfs(); |
349 let store_vfs = repo.store_vfs(); |
325 let res: Vec<_> = ds_status |
350 let res: Vec<_> = take(&mut ds_status.unsure) |
326 .unsure |
|
327 .into_par_iter() |
351 .into_par_iter() |
328 .map(|to_check| { |
352 .map(|to_check| { |
329 // The compiler seems to get a bit confused with complex |
353 // The compiler seems to get a bit confused with complex |
330 // inference when using a parallel iterator + map |
354 // inference when using a parallel iterator + map |
331 // + map_err + collect, so let's just inline some of the |
355 // + map_err + collect, so let's just inline some of the |
368 } |
392 } |
369 } |
393 } |
370 } |
394 } |
371 } |
395 } |
372 |
396 |
373 let relative_status = config |
|
374 .get_option(b"commands", b"status.relative")? |
|
375 .expect("commands.status.relative should have a default value"); |
|
376 |
|
377 let relativize_paths = relative_status || { |
|
378 // See in Python code with `getuipathfn` usage in `commands.py`. |
|
379 let legacy_relative_behavior = args.contains_id("file"); |
|
380 match relative_paths(invocation.config)? { |
|
381 RelativePaths::Legacy => legacy_relative_behavior, |
|
382 RelativePaths::Bool(v) => v, |
|
383 } |
|
384 }; |
|
385 |
|
386 let output = DisplayStatusPaths { |
|
387 ui, |
|
388 no_status, |
|
389 relativize: if relativize_paths { |
|
390 Some(RelativizePaths::new(repo)?) |
|
391 } else { |
|
392 None |
|
393 }, |
|
394 print0, |
|
395 }; |
|
396 if display_states.modified { |
|
397 output.display(b"M ", "status.modified", ds_status.modified)?; |
|
398 } |
|
399 if display_states.added { |
|
400 output.display(b"A ", "status.added", ds_status.added)?; |
|
401 } |
|
402 if display_states.removed { |
|
403 output.display(b"R ", "status.removed", ds_status.removed)?; |
|
404 } |
|
405 if display_states.deleted { |
|
406 output.display(b"! ", "status.deleted", ds_status.deleted)?; |
|
407 } |
|
408 if display_states.unknown { |
|
409 output.display(b"? ", "status.unknown", ds_status.unknown)?; |
|
410 } |
|
411 if display_states.ignored { |
|
412 output.display(b"I ", "status.ignored", ds_status.ignored)?; |
|
413 } |
|
414 if display_states.clean { |
|
415 output.display(b"C ", "status.clean", ds_status.clean)?; |
|
416 } |
|
417 |
|
418 let dirstate_write_needed = ds_status.dirty; |
397 let dirstate_write_needed = ds_status.dirty; |
419 let filesystem_time_at_status_start = |
398 let filesystem_time_at_status_start = |
420 ds_status.filesystem_time_at_status_start; |
399 ds_status.filesystem_time_at_status_start; |
|
400 |
|
401 output.output(display_states, ds_status)?; |
421 |
402 |
422 Ok(( |
403 Ok(( |
423 fixup, |
404 fixup, |
424 dirstate_write_needed, |
405 dirstate_write_needed, |
425 filesystem_time_at_status_start, |
406 filesystem_time_at_status_start, |
626 )? |
607 )? |
627 } |
608 } |
628 } |
609 } |
629 Ok(()) |
610 Ok(()) |
630 } |
611 } |
|
612 |
|
613 fn output( |
|
614 &mut self, |
|
615 display_states: DisplayStates, |
|
616 ds_status: DirstateStatus, |
|
617 ) -> Result<(), CommandError> { |
|
618 if display_states.modified { |
|
619 self.display(b"M ", "status.modified", ds_status.modified)?; |
|
620 } |
|
621 if display_states.added { |
|
622 self.display(b"A ", "status.added", ds_status.added)?; |
|
623 } |
|
624 if display_states.removed { |
|
625 self.display(b"R ", "status.removed", ds_status.removed)?; |
|
626 } |
|
627 if display_states.deleted { |
|
628 self.display(b"! ", "status.deleted", ds_status.deleted)?; |
|
629 } |
|
630 if display_states.unknown { |
|
631 self.display(b"? ", "status.unknown", ds_status.unknown)?; |
|
632 } |
|
633 if display_states.ignored { |
|
634 self.display(b"I ", "status.ignored", ds_status.ignored)?; |
|
635 } |
|
636 if display_states.clean { |
|
637 self.display(b"C ", "status.clean", ds_status.clean)?; |
|
638 } |
|
639 Ok(()) |
|
640 } |
631 } |
641 } |
632 |
642 |
633 /// Outcome of the additional check for an ambiguous tracked file |
643 /// Outcome of the additional check for an ambiguous tracked file |
634 enum UnsureOutcome { |
644 enum UnsureOutcome { |
635 /// The file is actually clean |
645 /// The file is actually clean |