Skip to content

Commit ba7d9a4

Browse files
authored
Merge pull request #2589 from GitoxideLabs/fix-status-in-unborn-repo
Let is_dirty handle unborn HEADs
2 parents 8af2691 + db16a05 commit ba7d9a4

7 files changed

Lines changed: 111 additions & 37 deletions

File tree

gix-worktree-state/tests/state/checkout.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,8 @@ use std::sync::LazyLock;
1515

1616
use crate::fixture_path;
1717

18-
static DRIVER: LazyLock<PathBuf> = LazyLock::new(|| {
19-
let mut cargo = std::process::Command::new(env!("CARGO"));
20-
let res = cargo
21-
.args(["build", "-p=gix-filter", "--example", "arrow"])
22-
.status()
23-
.expect("cargo should run fine");
24-
assert!(res.success(), "cargo invocation should be successful");
25-
26-
let path = PathBuf::from(env!("CARGO_TARGET_TMPDIR"))
27-
.ancestors()
28-
.nth(1)
29-
.expect("first parent in target dir")
30-
.join("debug")
31-
.join("examples")
32-
.join(if cfg!(windows) { "arrow.exe" } else { "arrow" });
33-
assert!(path.is_file(), "Expecting driver to be located at {}", path.display());
34-
path
35-
});
18+
static DRIVER: LazyLock<PathBuf> =
19+
LazyLock::new(|| gix_testtools::build_example_for_test("gix-filter", "arrow", env!("CARGO_TARGET_TMPDIR")));
3620

3721
fn driver_exe() -> String {
3822
let mut exe = DRIVER.to_string_lossy().into_owned();

gix-worktree-stream/tests/stream.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -309,24 +309,8 @@ mod from_tree {
309309
}
310310
}
311311

312-
static DRIVER: LazyLock<PathBuf> = LazyLock::new(|| {
313-
let mut cargo = std::process::Command::new(env!("CARGO"));
314-
let res = cargo
315-
.args(["build", "-p=gix-filter", "--example", "arrow"])
316-
.status()
317-
.expect("cargo should run fine");
318-
assert!(res.success(), "cargo invocation should be successful");
319-
320-
let path = PathBuf::from(env!("CARGO_TARGET_TMPDIR"))
321-
.ancestors()
322-
.nth(1)
323-
.expect("first parent in target dir")
324-
.join("debug")
325-
.join("examples")
326-
.join(if cfg!(windows) { "arrow.exe" } else { "arrow" });
327-
assert!(path.is_file(), "Expecting driver to be located at {}", path.display());
328-
path
329-
});
312+
static DRIVER: LazyLock<PathBuf> =
313+
LazyLock::new(|| gix_testtools::build_example_for_test("gix-filter", "arrow", env!("CARGO_TARGET_TMPDIR")));
330314

331315
struct TeeToMemory<R> {
332316
read: R,

gix/src/status/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub mod is_dirty {
167167
// optimal resource usage.
168168
pub fn is_dirty(&self) -> Result<bool, Error> {
169169
{
170-
let head_tree_id = self.head_tree_id()?;
170+
let head_tree_id = self.head_tree_id_or_empty()?;
171171
let mut index_is_dirty = false;
172172

173173
// Run this first as there is a high likelihood to find something, and it's very fast.
49.5 KB
Binary file not shown.

gix/tests/fixtures/make_status_repos.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ git init untracked-unborn
3636
touch untracked
3737
)
3838

39+
git init added-unborn
40+
(cd added-unborn
41+
echo content >added
42+
mkdir dir
43+
echo content >dir/nested
44+
git add added dir/nested
45+
)
46+
3947
git init untracked-added
4048
(cd untracked-added
4149
echo content >added

gix/tests/gix/status.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,40 @@ mod into_iter {
241241
Ok(())
242242
}
243243

244+
#[test]
245+
fn added_unborn() -> crate::Result {
246+
let repo = repo("added-unborn")?;
247+
let mut status = repo.status(gix::progress::Discard)?.into_iter(None)?;
248+
let mut items: Vec<_> = status.by_ref().filter_map(Result::ok).collect();
249+
items.sort_by(|a, b| a.location().cmp(b.location()));
250+
let snapshot = gix_testtools::normalize_debug_snapshot(&items).0;
251+
insta::assert_snapshot!(snapshot, @r#"
252+
[
253+
TreeIndex(
254+
Addition {
255+
location: "added",
256+
index: 0,
257+
entry_mode: Mode(
258+
FILE,
259+
),
260+
id: Oid(1),
261+
},
262+
),
263+
TreeIndex(
264+
Addition {
265+
location: "dir/nested",
266+
index: 1,
267+
entry_mode: Mode(
268+
FILE,
269+
),
270+
id: Oid(1),
271+
},
272+
),
273+
]
274+
"#);
275+
Ok(())
276+
}
277+
244278
#[test]
245279
fn untracked_added() -> crate::Result {
246280
let repo = repo("untracked-added")?;
@@ -518,6 +552,28 @@ mod is_dirty {
518552
Ok(())
519553
}
520554

555+
#[test]
556+
fn unborn_head_is_not_an_error() -> crate::Result {
557+
let repo = repo("untracked-unborn")?;
558+
559+
assert!(
560+
!repo.is_dirty()?,
561+
"untracked files aren't taken into consideration, even if HEAD is unborn"
562+
);
563+
Ok(())
564+
}
565+
566+
#[test]
567+
fn added_files_in_unborn_head_are_dirty() -> crate::Result {
568+
let repo = repo("added-unborn")?;
569+
570+
assert!(
571+
repo.is_dirty()?,
572+
"files added to the index make an unborn repository dirty"
573+
);
574+
Ok(())
575+
}
576+
521577
#[test]
522578
fn index_changed() -> crate::Result {
523579
let repo = repo("git-mv")?;

tests/tools/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,48 @@ pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Sen
6161
/// This is useful for computing values based on the fixture contents.
6262
pub type PostResult<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
6363

64+
/// Build `example` from `package` and copy the executable to this test process' temporary target directory.
65+
///
66+
/// The returned executable path is stable for the lifetime of the test process and avoids races with other
67+
/// concurrently running tests that may cause Cargo to update the shared example binary in `target/debug/examples`.
68+
pub fn build_example_for_test(package: &str, example: &str, target_tmpdir: impl Into<PathBuf>) -> PathBuf {
69+
let mut cargo = std::process::Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from(env!("CARGO"))));
70+
let res = cargo
71+
.args(["build", "-p", package, "--example", example])
72+
.status()
73+
.expect("cargo should run fine");
74+
assert!(res.success(), "cargo invocation should be successful");
75+
76+
let target_tmpdir = target_tmpdir.into();
77+
let shared_path = target_tmpdir
78+
.ancestors()
79+
.nth(1)
80+
.expect("first parent in target dir")
81+
.join("debug")
82+
.join("examples")
83+
.join(format!("{example}{}", std::env::consts::EXE_SUFFIX));
84+
85+
let stable_path = target_tmpdir.join(format!(
86+
"{example}-{}{}",
87+
std::process::id(),
88+
std::env::consts::EXE_SUFFIX
89+
));
90+
let mut last_err = None;
91+
for _ in 0..10 {
92+
match std::fs::copy(&shared_path, &stable_path) {
93+
Ok(_) => return stable_path,
94+
Err(err) => {
95+
last_err = Some(err);
96+
std::thread::sleep(Duration::from_millis(50));
97+
}
98+
}
99+
}
100+
panic!(
101+
"driver at {} could be copied for stable test execution: {last_err:?}",
102+
shared_path.display()
103+
);
104+
}
105+
64106
/// Indicates the state of a fixture when a closure is called.
65107
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66108
pub enum FixtureState<'a> {

0 commit comments

Comments
 (0)