Skip to content

Commit a3afaa4

Browse files
committed
Merge branch 'submodule-active'
2 parents 169228b + af1cab3 commit a3afaa4

File tree

55 files changed

+1200
-311
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1200
-311
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ jobs:
188188
- name: Install Rust
189189
run: rustup update stable && rustup default stable && rustup target add ${{ matrix.target }}
190190
- uses: Swatinem/rust-cache@v2
191-
- run: set +x; for name in gix-actor gix-attributes gix-bitmap gix-chunk gix-command gix-commitgraph gix-date gix-glob gix-hash gix-hashtable gix-mailmap gix-object gix-packetline gix-path gix-pathspec gix-quote gix-refspec gix-revision gix-traverse gix-validate; do (cd $name && cargo build --target ${{ matrix.target }}); done
191+
- run: set +x; for name in gix-actor gix-attributes gix-bitmap gix-chunk gix-command gix-commitgraph gix-date gix-glob gix-hash gix-hashtable gix-mailmap gix-object gix-packetline gix-path gix-quote gix-refspec gix-revision gix-traverse gix-validate; do (cd $name && cargo build --target ${{ matrix.target }}); done
192192
name: crates without feature toggles
193193
- run: set +x; for feature in progress fs-walkdir-parallel parallel io-pipe crc32 zlib zlib-rust-backend fast-sha1 rustsha1 cache-efficiency-debug; do (cd gix-features && cargo build --features $feature --target ${{ matrix.target }}); done
194194
name: features of gix-features

Cargo.lock

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ tracing = { version = "0.1.37", optional = true }
183183
owo-colors = "3.5.0"
184184
tabled = { version = "0.10.0", default-features = false }
185185

186+
once_cell = "1.18.0"
186187
document-features = { version = "0.2.0", optional = true }
187188

188189
[profile.dev.package]

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

+15-7
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

+1
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;
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

+1-1
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();
+45-26
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+
}

0 commit comments

Comments
 (0)