Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ca972a2

Browse files
committed
adapt to changes in gix
1 parent a7d0e44 commit ca972a2

10 files changed

Lines changed: 184 additions & 106 deletions

File tree

gitoxide-core/src/query/engine/command.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,22 @@ impl query::Engine {
1717
mut progress: impl gix::Progress,
1818
) -> anyhow::Result<()> {
1919
match cmd {
20-
Command::TracePath { mut spec } => {
20+
Command::TracePath { spec } => {
2121
let is_excluded = spec.is_excluded();
22-
let relpath = spec
23-
.normalize(
24-
self.repo.prefix()?.unwrap_or_default().as_ref(),
25-
self.repo.work_dir().unwrap_or_else(|| self.repo.git_dir()),
22+
// Just to get the normalized version of the path with everything auto-configured.
23+
let relpath = self
24+
.repo
25+
.pathspec(
26+
Some(spec.to_bstring()),
27+
false,
28+
&gix::index::State::new(self.repo.object_hash()),
2629
)?
27-
.path();
30+
.search()
31+
.patterns()
32+
.next()
33+
.expect("exactly one")
34+
.path()
35+
.to_owned();
2836
if relpath.is_empty() || is_excluded {
2937
bail!("Invalid pathspec {spec} - path must not be empty, not be excluded, and wildcards are taken literally")
3038
}
@@ -36,7 +44,7 @@ impl query::Engine {
3644
|r| r.get(0),
3745
)
3846
.optional()?
39-
.context("Path not found anywhere in recorded history")?;
47+
.with_context(|| format!("Path '{relpath}' not found anywhere in recorded history"))?;
4048

4149
let mut by_file_id = self
4250
.con

gitoxide-core/src/query/engine/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub enum Command {
66
}
77

88
pub(crate) mod update;
9+
910
pub use update::update;
1011

1112
mod command;
Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::OutputFormat;
2+
use gix::repository::IndexPersistedOrInMemory;
23

34
pub struct Options {
45
pub format: OutputFormat,
@@ -8,17 +9,19 @@ pub struct Options {
89
pub(crate) mod function {
910
use std::{io, path::Path};
1011

11-
use anyhow::bail;
12+
use anyhow::{anyhow, bail};
13+
use gix::bstr::BStr;
1214
use gix::prelude::FindExt;
1315

16+
use crate::repository::PathsOrPatterns;
1417
use crate::{
1518
repository::attributes::query::{attributes_cache, Options},
1619
OutputFormat,
1720
};
1821

1922
pub fn query(
2023
repo: gix::Repository,
21-
pathspecs: impl Iterator<Item = gix::pathspec::Pattern>,
24+
input: PathsOrPatterns,
2225
mut out: impl io::Write,
2326
mut err: impl io::Write,
2427
Options { format, statistics }: Options,
@@ -27,32 +30,33 @@ pub(crate) mod function {
2730
bail!("JSON output isn't implemented yet");
2831
}
2932

30-
let mut cache = attributes_cache(&repo)?;
33+
let (mut cache, index) = attributes_cache(&repo)?;
3134
let mut matches = cache.attribute_matches();
32-
// TODO(pathspec): The search is just used as a shortcut to normalization, but one day should be used for an actual search.
33-
let search = gix::pathspec::Search::from_specs(
34-
pathspecs,
35-
repo.prefix()?.as_deref(),
36-
repo.work_dir().unwrap_or_else(|| repo.git_dir()),
37-
)?;
3835

39-
for spec in search.into_patterns() {
40-
let is_dir = gix::path::from_bstr(spec.path()).metadata().ok().map(|m| m.is_dir());
41-
let entry = cache.at_entry(spec.path(), is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?;
36+
match input {
37+
PathsOrPatterns::Paths(paths) => {
38+
for path in paths {
39+
let is_dir = gix::path::from_bstr(path.as_ref()).metadata().ok().map(|m| m.is_dir());
4240

43-
if !entry.matching_attributes(&mut matches) {
44-
continue;
41+
let entry = cache.at_entry(path.as_slice(), is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?;
42+
if !entry.matching_attributes(&mut matches) {
43+
continue;
44+
}
45+
print_match(&matches, path.as_ref(), &mut out)?;
46+
}
4547
}
46-
for m in matches.iter() {
47-
writeln!(
48-
out,
49-
"{}:{}:{}\t{}\t{}",
50-
m.location.source.map(Path::to_string_lossy).unwrap_or_default(),
51-
m.location.sequence_number,
52-
m.pattern,
53-
spec.path(),
54-
m.assignment
55-
)?;
48+
PathsOrPatterns::Patterns(patterns) => {
49+
let mut pathspec = repo.pathspec(patterns, true, &index)?;
50+
for (path, _entry) in pathspec
51+
.index_entries_with_paths(&index)
52+
.ok_or_else(|| anyhow!("Pathspec didn't match a single path in the index"))?
53+
{
54+
let entry = cache.at_entry(path, Some(false), |oid, buf| repo.objects.find_blob(oid, buf))?;
55+
if !entry.matching_attributes(&mut matches) {
56+
continue;
57+
}
58+
print_match(&matches, path, &mut out)?;
59+
}
5660
}
5761
}
5862

@@ -62,11 +66,32 @@ pub(crate) mod function {
6266
}
6367
Ok(())
6468
}
69+
70+
fn print_match(
71+
matches: &gix::attrs::search::Outcome,
72+
path: &BStr,
73+
mut out: impl std::io::Write,
74+
) -> std::io::Result<()> {
75+
for m in matches.iter() {
76+
writeln!(
77+
out,
78+
"{}:{}:{}\t{}\t{}",
79+
m.location.source.map(Path::to_string_lossy).unwrap_or_default(),
80+
m.location.sequence_number,
81+
m.pattern,
82+
path,
83+
m.assignment
84+
)?;
85+
}
86+
Ok(())
87+
}
6588
}
6689

67-
pub(crate) fn attributes_cache(repo: &gix::Repository) -> anyhow::Result<gix::worktree::Cache> {
90+
pub(crate) fn attributes_cache(
91+
repo: &gix::Repository,
92+
) -> anyhow::Result<(gix::worktree::Cache, IndexPersistedOrInMemory)> {
6893
let index = repo.index_or_load_from_head()?;
69-
Ok(repo.attributes(
94+
let cache = repo.attributes(
7095
&index,
7196
if repo.is_bare() {
7297
gix::worktree::cache::state::attributes::Source::IdMapping
@@ -75,5 +100,6 @@ pub(crate) fn attributes_cache(repo: &gix::Repository) -> anyhow::Result<gix::wo
75100
},
76101
gix::worktree::cache::state::ignore::Source::IdMapping,
77102
None,
78-
)?)
103+
)?;
104+
Ok((cache, index))
79105
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ pub(crate) mod function {
182182
}
183183
});
184184

185-
let mut cache = attributes_cache(&repo)?;
185+
let (mut cache, _index) = attributes_cache(&repo)?;
186186
let mut matches = cache.attribute_matches();
187187
let mut progress = progress.add_child("validate");
188188
let mut mismatches = Vec::new();
Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::io;
22

3-
use anyhow::bail;
3+
use anyhow::{anyhow, bail};
4+
use gix::bstr::BStr;
45
use gix::prelude::FindExt;
56

7+
use crate::repository::PathsOrPatterns;
68
use crate::OutputFormat;
79

810
pub mod query {
@@ -20,7 +22,7 @@ pub mod query {
2022

2123
pub fn query(
2224
repo: gix::Repository,
23-
pathspecs: impl Iterator<Item = gix::pathspec::Pattern>,
25+
input: PathsOrPatterns,
2426
mut out: impl io::Write,
2527
mut err: impl io::Write,
2628
query::Options {
@@ -41,30 +43,29 @@ pub fn query(
4143
Default::default(),
4244
)?;
4345

44-
// TODO(pathspec): actually use the search to find items. This looks like `gix` capabilities to put it all together.
45-
let search = gix::pathspec::Search::from_specs(
46-
pathspecs,
47-
repo.prefix()?.as_deref(),
48-
repo.work_dir().unwrap_or_else(|| repo.git_dir()),
49-
)?;
50-
51-
for spec in search.into_patterns() {
52-
let path = spec.path();
53-
let is_dir = gix::path::from_bstr(path).metadata().ok().map(|m| m.is_dir());
54-
let entry = cache.at_entry(path, is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?;
55-
let match_ = entry
56-
.matching_exclude_pattern()
57-
.and_then(|m| (show_ignore_patterns || !m.pattern.is_negative()).then_some(m));
58-
match match_ {
59-
Some(m) => writeln!(
60-
out,
61-
"{}:{}:{}\t{}",
62-
m.source.map(std::path::Path::to_string_lossy).unwrap_or_default(),
63-
m.sequence_number,
64-
m.pattern,
65-
path
66-
)?,
67-
None => writeln!(out, "::\t{path}")?,
46+
match input {
47+
PathsOrPatterns::Paths(paths) => {
48+
for path in paths {
49+
let is_dir = gix::path::from_bstr(path.as_ref()).metadata().ok().map(|m| m.is_dir());
50+
let entry = cache.at_entry(path.as_slice(), is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?;
51+
let match_ = entry
52+
.matching_exclude_pattern()
53+
.and_then(|m| (show_ignore_patterns || !m.pattern.is_negative()).then_some(m));
54+
print_match(match_, path.as_ref(), &mut out)?;
55+
}
56+
}
57+
PathsOrPatterns::Patterns(patterns) => {
58+
for (path, _entry) in repo
59+
.pathspec(patterns.into_iter(), repo.work_dir().is_some(), &index)?
60+
.index_entries_with_paths(&index)
61+
.ok_or_else(|| anyhow!("Pathspec didn't yield any entry"))?
62+
{
63+
let entry = cache.at_entry(path, Some(false), |oid, buf| repo.objects.find_blob(oid, buf))?;
64+
let match_ = entry
65+
.matching_exclude_pattern()
66+
.and_then(|m| (show_ignore_patterns || !m.pattern.is_negative()).then_some(m));
67+
print_match(match_, path, &mut out)?;
68+
}
6869
}
6970
}
7071

@@ -74,3 +75,21 @@ pub fn query(
7475
}
7576
Ok(())
7677
}
78+
79+
fn print_match(
80+
m: Option<gix::ignore::search::Match<'_>>,
81+
path: &BStr,
82+
mut out: impl std::io::Write,
83+
) -> std::io::Result<()> {
84+
match m {
85+
Some(m) => writeln!(
86+
out,
87+
"{}:{}:{}\t{}",
88+
m.source.map(std::path::Path::to_string_lossy).unwrap_or_default(),
89+
m.sequence_number,
90+
m.pattern,
91+
path
92+
),
93+
None => writeln!(out, "::\t{path}"),
94+
}
95+
}

gitoxide-core/src/repository/index/entries.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum Attributes {
1616
}
1717

1818
pub(crate) mod function {
19+
use gix::bstr::BString;
1920
use std::collections::BTreeSet;
2021
use std::{
2122
borrow::Cow,
@@ -28,7 +29,7 @@ pub(crate) mod function {
2829

2930
pub fn entries(
3031
repo: gix::Repository,
31-
pathspecs: Vec<gix::pathspec::Pattern>,
32+
pathspecs: Vec<BString>,
3233
out: impl std::io::Write,
3334
mut err: impl std::io::Write,
3435
Options {
@@ -40,10 +41,12 @@ pub(crate) mod function {
4041
) -> anyhow::Result<()> {
4142
use crate::OutputFormat::*;
4243
let index = repo.index_or_load_from_head()?;
44+
let pathspec = repo.pathspec(pathspecs, false, &index)?;
4345
let mut cache = attributes
4446
.or_else(|| {
45-
pathspecs
46-
.iter()
47+
pathspec
48+
.search()
49+
.patterns()
4750
.any(|spec| !spec.attributes.is_empty())
4851
.then_some(Attributes::Index)
4952
})
@@ -85,11 +88,7 @@ pub(crate) mod function {
8588
if let Json = format {
8689
out.write_all(b"[\n")?;
8790
}
88-
let mut search = gix::pathspec::Search::from_specs(
89-
pathspecs,
90-
repo.prefix()?.as_deref(),
91-
gix::path::realpath(repo.work_dir().unwrap_or_else(|| repo.git_dir()))?.as_ref(), // TODO(pathspec): this setup needs `gix`.
92-
)?;
91+
let (mut search, _cache) = pathspec.into_parts();
9392
let mut all_attrs = statistics.then(BTreeSet::new);
9493
if let Some(entries) = index.prefixed_entries(search.common_prefix()) {
9594
stats.entries_after_prune = entries.len();

gitoxide-core/src/repository/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use gix::bstr::BString;
12
use std::path::PathBuf;
23

34
use anyhow::{Context as AnyhowContext, Result};
@@ -11,6 +12,11 @@ pub fn init(directory: Option<PathBuf>) -> Result<gix::discover::repository::Pat
1112
.with_context(|| "Repository initialization failed")
1213
}
1314

15+
pub enum PathsOrPatterns {
16+
Paths(Box<dyn std::iter::Iterator<Item = BString>>),
17+
Patterns(Vec<BString>),
18+
}
19+
1420
#[cfg(feature = "archive")]
1521
pub mod archive;
1622
pub mod commit;
@@ -27,6 +33,7 @@ pub mod fetch;
2733
pub use clone::function::clone;
2834
#[cfg(feature = "blocking-client")]
2935
pub use fetch::function::fetch;
36+
3037
pub mod commitgraph;
3138
pub mod index;
3239
pub mod mailmap;

0 commit comments

Comments
 (0)