(project: &Path, args: &[&str])
| 728 | } |
| 729 | |
| 730 | pub(crate) fn git(project: &Path, args: &[&str]) { |
| 731 | assert!( |
| 732 | project.is_dir(), |
| 733 | "git cwd {project:?} should exist before running git {args:?}" |
| 734 | ); |
| 735 | let git = crate::common::git_program(); |
| 736 | // Retry a transient spawn ENOENT: under heavy parallel test load the |
| 737 | // initial fork/exec can spuriously fail with "No such file or directory". |
| 738 | let mut last_err: Option<std::io::Error> = None; |
| 739 | let mut output = None; |
| 740 | for attempt in 0..5 { |
| 741 | match Command::new(&git).args(args).current_dir(project).output() { |
| 742 | Ok(out) => { |
| 743 | output = Some(out); |
| 744 | break; |
| 745 | } |
| 746 | Err(err) if err.kind() == std::io::ErrorKind::NotFound && attempt < 4 => { |
| 747 | last_err = Some(err); |
| 748 | thread::sleep(std::time::Duration::from_millis(20 * (attempt + 1))); |
| 749 | } |
| 750 | Err(err) => panic!("failed to run git {args:?} (program {git:?}): {err}"), |
| 751 | } |
| 752 | } |
| 753 | let output = output.unwrap_or_else(|| { |
| 754 | panic!("failed to run git {args:?} (program {git:?}) after retries: {last_err:?}") |
| 755 | }); |
| 756 | assert!( |
| 757 | output.status.success(), |
| 758 | "git {args:?} failed\nstdout:\n{}\nstderr:\n{}", |
| 759 | String::from_utf8_lossy(&output.stdout), |
| 760 | String::from_utf8_lossy(&output.stderr) |
| 761 | ); |
| 762 | } |
| 763 | |
| 764 | pub(crate) fn commit_all(project: &Path, message: &str) { |
| 765 | git(project, &["add", "."]); |
no test coverage detected