Skip to content

Commit 596ff7a

Browse files
committed
feat: gix attributes validate-baseline works in bare repostiories.
1 parent 39b0ba5 commit 596ff7a

File tree

2 files changed

+68
-12
lines changed

2 files changed

+68
-12
lines changed

gitoxide-core/src/repository/attributes/query.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::OutputFormat;
2+
use gix::odb::FindExt;
23

34
pub struct Options {
45
pub format: OutputFormat,
@@ -58,11 +59,54 @@ pub(crate) mod function {
5859
}
5960
}
6061

62+
pub(crate) enum Index {
63+
Shared(gix::worktree::Index),
64+
Owned(gix::index::File),
65+
}
66+
67+
impl std::ops::Deref for Index {
68+
type Target = gix::index::File;
69+
70+
fn deref(&self) -> &Self::Target {
71+
match self {
72+
Index::Shared(i) => i,
73+
Index::Owned(i) => i,
74+
}
75+
}
76+
}
77+
78+
impl Index {
79+
pub fn into_owned(self) -> gix::index::File {
80+
match self {
81+
Index::Shared(i) => gix::index::File::clone(&i),
82+
Index::Owned(i) => i,
83+
}
84+
}
85+
}
86+
87+
pub(crate) fn index_on_demand(repo: &gix::Repository) -> anyhow::Result<Index> {
88+
Ok(match repo.index() {
89+
Ok(index) => Index::Shared(index),
90+
Err(gix::worktree::open_index::Error::IndexFile(_)) => {
91+
let tree = repo.head_commit()?.tree_id()?;
92+
Index::Owned(gix::index::File::from_state(
93+
gix::index::State::from_tree(&tree, |oid, buf| repo.objects.find_tree_iter(oid, buf).ok())?,
94+
repo.git_dir().join("index"),
95+
))
96+
}
97+
Err(err) => return Err(err.into()),
98+
})
99+
}
100+
61101
pub(crate) fn attributes_cache(repo: &gix::Repository) -> anyhow::Result<gix::worktree::Cache> {
62-
let index = repo.index()?;
102+
let index = index_on_demand(repo)?;
63103
Ok(repo.attributes(
64104
&index,
65-
gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping,
105+
if repo.is_bare() {
106+
gix::worktree::cache::state::attributes::Source::IdMapping
107+
} else {
108+
gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping
109+
},
66110
gix::worktree::cache::state::ignore::Source::IdMapping,
67111
None,
68112
)?)

gitoxide-core/src/repository/attributes/validate_baseline.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) mod function {
1919
use gix::odb::FindExt;
2020
use gix::Progress;
2121

22-
use crate::repository::attributes::query::attributes_cache;
22+
use crate::repository::attributes::query::{attributes_cache, index_on_demand};
2323
use crate::repository::attributes::validate_baseline::Options;
2424
use crate::OutputFormat;
2525

@@ -32,21 +32,30 @@ pub(crate) mod function {
3232
Options {
3333
format,
3434
statistics,
35-
ignore,
35+
mut ignore,
3636
}: Options,
3737
) -> anyhow::Result<()> {
3838
if format != OutputFormat::Human {
3939
bail!("JSON output isn't implemented yet");
4040
}
4141

42+
if repo.is_bare() {
43+
writeln!(
44+
err,
45+
"Repo {:?} is bare - disabling git-ignore baseline as `git check-ignore` needs a worktree",
46+
repo.path()
47+
)
48+
.ok();
49+
ignore = false;
50+
}
4251
let mut num_entries = None;
4352
let pathspecs = pathspecs
4453
.map(|i| anyhow::Result::Ok(Box::new(i) as Box<dyn Iterator<Item = gix::path::Spec> + Send + 'static>))
4554
.unwrap_or_else({
4655
let repo = repo.clone();
4756
let num_entries = &mut num_entries;
4857
move || -> anyhow::Result<_> {
49-
let index = repo.open_index()?;
58+
let index = index_on_demand(&repo)?.into_owned();
5059
let (entries, path_backing) = index.into_parts().0.into_entries();
5160
*num_entries = Some(entries.len());
5261
Ok(Box::new(entries.into_iter().map(move |e| {
@@ -55,15 +64,11 @@ pub(crate) mod function {
5564
}
5665
})?;
5766

58-
let work_dir = repo
59-
.work_dir()
60-
.map(ToOwned::to_owned)
61-
.ok_or_else(|| anyhow!("repository at {:?} must have a worktree checkout", repo.path()))?;
6267
let (tx_base, rx_base) = std::sync::mpsc::channel::<(String, Baseline)>();
6368
let feed_attrs = {
6469
let (tx, rx) = std::sync::mpsc::sync_channel::<gix::path::Spec>(1);
6570
std::thread::spawn({
66-
let path = work_dir.clone();
71+
let path = repo.path().to_owned();
6772
let tx_base = tx_base.clone();
6873
let mut progress = progress.add_child("attributes");
6974
move || -> anyhow::Result<()> {
@@ -106,10 +111,17 @@ pub(crate) mod function {
106111
});
107112
tx
108113
};
114+
let work_dir = ignore
115+
.then(|| {
116+
repo.work_dir()
117+
.map(ToOwned::to_owned)
118+
.ok_or_else(|| anyhow!("repository at {:?} must have a worktree checkout", repo.path()))
119+
})
120+
.transpose()?;
109121
let feed_excludes = ignore.then(|| {
110122
let (tx, rx) = std::sync::mpsc::sync_channel::<gix::path::Spec>(1);
111123
std::thread::spawn({
112-
let path = work_dir.clone();
124+
let path = work_dir.expect("present if we are here");
113125
let tx_base = tx_base.clone();
114126
let mut progress = progress.add_child("excludes");
115127
move || -> anyhow::Result<()> {
@@ -239,7 +251,7 @@ pub(crate) mod function {
239251
}
240252
bail!(
241253
"{}: Validation failed with {} mismatches out of {}",
242-
gix::path::realpath(&work_dir).unwrap_or(work_dir).display(),
254+
gix::path::realpath(repo.work_dir().unwrap_or(repo.git_dir()))?.display(),
243255
mismatches.len(),
244256
progress
245257
.counter()

0 commit comments

Comments
 (0)