Skip to content

tree -> index diff for status #1368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions gitoxide-core/src/repository/attributes/validate_baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,13 @@ pub(crate) mod function {
}

fn parse_exclude(line: &str) -> Option<(String, Baseline)> {
let (left, value) = line.split_at(line.find(|c| c == '\t')?);
let (left, value) = line.split_at(line.find('\t')?);
let value = &value[1..];

let location = if left == "::" {
None
} else {
let mut tokens = left.split(|b| b == ':');
let mut tokens = left.split(':');
let source = tokens.next()?;
let line_number: usize = tokens.next()?.parse().ok()?;
let pattern = tokens.next()?;
Expand Down Expand Up @@ -363,8 +363,8 @@ pub(crate) mod function {
"unspecified" => StateRef::Unspecified,
_ => StateRef::from_bytes(info.as_bytes()),
};
path = path.trim_end_matches(|b| b == ':');
let attr = attr.trim_end_matches(|b| b == ':');
path = path.trim_end_matches(':');
let attr = attr.trim_end_matches(':');
let assignment = gix::attrs::AssignmentRef {
name: gix::attrs::NameRef::try_from(attr.as_bytes().as_bstr()).ok()?,
state,
Expand Down
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/index/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ pub(crate) mod function {

#[cfg(feature = "serde")]
fn to_json(
mut out: &mut impl std::io::Write,
out: &mut impl std::io::Write,
index: &gix::index::File,
entry: &gix::index::Entry,
attrs: Option<Attrs>,
Expand All @@ -338,7 +338,7 @@ pub(crate) mod function {
}

serde_json::to_writer(
&mut out,
&mut *out,
&Entry {
stat: &entry.stat,
hex_id: entry.id.to_hex().to_string(),
Expand Down
2 changes: 1 addition & 1 deletion gix-config/src/file/section/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl<'a> Section<'a> {
/// Stream ourselves to the given `out`, in order to reproduce this section mostly losslessly
/// as it was parsed.
pub fn write_to(&self, mut out: &mut dyn std::io::Write) -> std::io::Result<()> {
self.header.write_to(&mut out)?;
self.header.write_to(&mut *out)?;

if self.body.0.is_empty() {
return Ok(());
Expand Down
5 changes: 3 additions & 2 deletions gix-config/src/file/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl File<'_> {
pub fn write_to_filter(
&self,
mut out: &mut dyn std::io::Write,
mut filter: &mut dyn FnMut(&Section<'_>) -> bool,
filter: &mut dyn FnMut(&Section<'_>) -> bool,
) -> std::io::Result<()> {
let nl = self.detect_newline_style();

Expand All @@ -27,7 +27,8 @@ impl File<'_> {
event.write_to(&mut out)?;
}

if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true) && self.sections.values().any(&mut filter)
if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true)
&& self.sections.values().any(&mut *filter)
{
out.write_all(nl)?;
}
Expand Down
6 changes: 3 additions & 3 deletions gix-config/src/parse/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Event<'_> {

/// Stream ourselves to the given `out`, in order to reproduce this event mostly losslessly
/// as it was parsed.
pub fn write_to(&self, mut out: &mut dyn std::io::Write) -> std::io::Result<()> {
pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> {
match self {
Self::ValueNotDone(e) => {
out.write_all(e.as_ref())?;
Expand All @@ -42,8 +42,8 @@ impl Event<'_> {
Self::Whitespace(e) | Self::Newline(e) | Self::Value(e) | Self::ValueDone(e) => out.write_all(e.as_ref()),
Self::KeyValueSeparator => out.write_all(b"="),
Self::SectionKey(k) => out.write_all(k.0.as_ref()),
Self::SectionHeader(h) => h.write_to(&mut out),
Self::Comment(c) => c.write_to(&mut out),
Self::SectionHeader(h) => h.write_to(out),
Self::Comment(c) => c.write_to(out),
}
}

Expand Down
30 changes: 15 additions & 15 deletions gix-config/src/parse/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,26 @@ pub type FrontMatterEvents<'a> = SmallVec<[Event<'a>; 8]>;
///
/// For concrete examples, some notable differences are:
/// - `git-config` sections permit subsections via either a quoted string
/// (`[some-section "subsection"]`) or via the deprecated dot notation
/// (`[some-section.subsection]`). Successful parsing these section names is not
/// well defined in typical `.ini` parsers. This parser will handle these cases
/// perfectly.
/// (`[some-section "subsection"]`) or via the deprecated dot notation
/// (`[some-section.subsection]`). Successful parsing these section names is not
/// well defined in typical `.ini` parsers. This parser will handle these cases
/// perfectly.
/// - Comment markers are not strictly defined either. This parser will always
/// and only handle a semicolon or octothorpe (also known as a hash or number
/// sign).
/// and only handle a semicolon or octothorpe (also known as a hash or number
/// sign).
/// - Global properties may be allowed in `.ini` parsers, but is strictly
/// disallowed by this parser.
/// disallowed by this parser.
/// - Only `\t`, `\n`, `\b` `\\` are valid escape characters.
/// - Quoted and semi-quoted values will be parsed (but quotes will be included
/// in event outputs). An example of a semi-quoted value is `5"hello world"`,
/// which should be interpreted as `5hello world` after
/// [normalization][crate::value::normalize()].
/// in event outputs). An example of a semi-quoted value is `5"hello world"`,
/// which should be interpreted as `5hello world` after
/// [normalization][crate::value::normalize()].
/// - Line continuations via a `\` character is supported (inside or outside of quotes)
/// - Whitespace handling similarly follows the `git-config` specification as
/// closely as possible, where excess whitespace after a non-quoted value are
/// trimmed, and line continuations onto a new line with excess spaces are kept.
/// closely as possible, where excess whitespace after a non-quoted value are
/// trimmed, and line continuations onto a new line with excess spaces are kept.
/// - Only equal signs (optionally padded by spaces) are valid name/value
/// delimiters.
/// delimiters.
///
/// Note that things such as case-sensitivity or duplicate sections are
/// _not_ handled. This parser is a low level _syntactic_ interpreter
Expand All @@ -62,8 +62,8 @@ pub type FrontMatterEvents<'a> = SmallVec<[Event<'a>; 8]>;
/// # Trait Implementations
///
/// - This struct does _not_ implement [`FromStr`] due to lifetime
/// constraints implied on the required `from_str` method. Instead, it provides
/// [`From<&'_ str>`].
/// constraints implied on the required `from_str` method. Instead, it provides
/// [`From<&'_ str>`].
///
/// # Idioms
///
Expand Down
12 changes: 6 additions & 6 deletions gix-fs/src/symlink.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::{io, io::ErrorKind::AlreadyExists, path::Path};

#[cfg(not(windows))]
/// Create a new symlink at `link` which points to `original`.
///
/// Note that `original` doesn't have to exist.
#[cfg(not(windows))]
pub fn create(original: &Path, link: &Path) -> io::Result<()> {
std::os::unix::fs::symlink(original, link)
}

#[cfg(not(windows))]
/// Remove a symlink.
///
/// Note that on only on windows this is special.
#[cfg(not(windows))]
pub fn remove(path: &Path) -> io::Result<()> {
std::fs::remove_file(path)
}
Expand All @@ -31,12 +31,12 @@ pub fn remove(path: &Path) -> io::Result<()> {
}
}

#[cfg(windows)]
/// Create a new symlink at `link` which points to `original`.
///
/// Note that if a symlink target (the `original`) isn't present on disk, it's assumed to be a
/// file, creating a dangling file symlink. This is similar to a dangling symlink on Unix,
/// which doesn't have to care about the target type though.
#[cfg(windows)]
pub fn create(original: &Path, link: &Path) -> io::Result<()> {
use std::os::windows::fs::{symlink_dir, symlink_file};
// TODO: figure out if links to links count as files or whatever they point at
Expand All @@ -53,20 +53,20 @@ pub fn create(original: &Path, link: &Path) -> io::Result<()> {
}
}

#[cfg(not(windows))]
/// Return true if `err` indicates that a file collision happened, i.e. a symlink couldn't be created as the `link`
/// already exists as filesystem object.
#[cfg(not(windows))]
pub fn is_collision_error(err: &std::io::Error) -> bool {
// TODO: use ::IsDirectory as well when stabilized instead of raw_os_error(), and ::FileSystemLoop respectively
err.kind() == AlreadyExists
|| err.raw_os_error() == Some(if cfg!(windows) { 5 } else { 21 })
|| err.raw_os_error() == Some(21)
|| err.raw_os_error() == Some(62) // no-follow on symlnk on mac-os
|| err.raw_os_error() == Some(40) // no-follow on symlnk on ubuntu
}

#[cfg(windows)]
/// Return true if `err` indicates that a file collision happened, i.e. a symlink couldn't be created as the `link`
/// already exists as filesystem object.
#[cfg(windows)]
pub fn is_collision_error(err: &std::io::Error) -> bool {
err.kind() == AlreadyExists || err.kind() == std::io::ErrorKind::PermissionDenied
}
2 changes: 1 addition & 1 deletion gix-ignore/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Search {
.transpose()?,
);
group.patterns.extend(pattern::List::<Ignore>::from_file(
&git_dir.join("info").join("exclude"),
git_dir.join("info").join("exclude"),
None,
follow_symlinks,
buf,
Expand Down
3 changes: 2 additions & 1 deletion gix-odb/tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ gix-date = { path = "../../gix-date" }
gix-object = { path = "../../gix-object" }
gix-pack = { path = "../../gix-pack" }

gix-testtools = { path = "../../tests/tools"}
gix-testtools = { path = "../../tests/tools" }
gix-actor = { path = "../../gix-actor" }
pretty_assertions = "1.0.0"
filetime = "0.2.15"
maplit = "1.0.2"
crossbeam-channel = "0.5.13"

Binary file not shown.
11 changes: 6 additions & 5 deletions gix-odb/tests/odb/regression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ mod repo_with_small_packs {
}

#[test]
#[cfg(feature = "internal-testing-gix-features-parallel")]
#[cfg(feature = "gix-features-parallel")]
fn multi_threaded_access_will_not_panic() -> crate::Result {
for arg in ["no", "without-multi-index"] {
let base = gix_testtools::scripted_fixture_read_only_with_args("make_repo_multi_index.sh", Some(arg))?
.join(".git")
.join("objects");
let base =
gix_testtools::scripted_fixture_read_only_with_args_standalone("make_repo_multi_index.sh", Some(arg))?
.join(".git")
.join("objects");
let store = gix_odb::at(base)?;
let (tx, barrier) = crossbeam_channel::unbounded::<()>();
let handles = (0..std::thread::available_parallelism()?.get()).map(|tid| {
Expand All @@ -36,7 +37,7 @@ mod repo_with_small_packs {
for id in store.iter()? {
let id = id?;
assert!(
store.try_find(id, &mut buf).is_ok(),
store.try_find(&id, &mut buf).is_ok(),
"Thread {} could not find {}",
tid,
id
Expand Down
58 changes: 32 additions & 26 deletions gix-pack/src/bundle/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ impl crate::Bundle {
/// * `progress` provides detailed progress information which can be discarded with [`gix_features::progress::Discard`].
/// * `should_interrupt` is checked regularly and when true, the whole operation will stop.
/// * `thin_pack_base_object_lookup` If set, we expect to see a thin-pack with objects that reference their base object by object id which is
/// expected to exist in the object database the bundle is contained within.
/// `options` further configure how the task is performed.
/// expected to exist in the object database the bundle is contained within.
/// `options` further configure how the task is performed.
///
/// # Note
///
Expand Down Expand Up @@ -300,31 +300,37 @@ impl crate::Bundle {
)?;
drop(pack_entries_iter);

let data_path = directory.join(format!("pack-{}.pack", outcome.data_hash.to_hex()));
let index_path = data_path.with_extension("idx");
let keep_path = data_path.with_extension("keep");
if outcome.num_objects == 0 {
WriteOutcome {
outcome,
data_path: None,
index_path: None,
keep_path: None,
}
} else {
let data_path = directory.join(format!("pack-{}.pack", outcome.data_hash.to_hex()));
let index_path = data_path.with_extension("idx");
let keep_path = data_path.with_extension("keep");

std::fs::write(&keep_path, b"")?;
Arc::try_unwrap(data_file)
.expect("only one handle left after pack was consumed")
.into_inner()
.into_inner()
.map_err(|err| Error::from(err.into_error()))?
.persist(&data_path)?;
index_file
.persist(&index_path)
.map_err(|err| {
progress.info(format!(
"pack file at {} is retained despite failing to move the index file into place. You can use plumbing to make it usable.",
data_path.display()
));
err
})?;
WriteOutcome {
outcome,
data_path: Some(data_path),
index_path: Some(index_path),
keep_path: Some(keep_path),
std::fs::write(&keep_path, b"")?;
Arc::try_unwrap(data_file)
.expect("only one handle left after pack was consumed")
.into_inner()
.into_inner()
.map_err(|err| Error::from(err.into_error()))?
.persist(&data_path)?;
index_file
.persist(&index_path)
.map_err(|err| {
gix_features::trace::warn!("pack file at \"{}\" is retained despite failing to move the index file into place. You can use plumbing to make it usable.",data_path.display());
err
})?;
WriteOutcome {
outcome,
data_path: Some(data_path),
index_path: Some(index_path),
keep_path: Some(keep_path),
}
}
}
None => WriteOutcome {
Expand Down
8 changes: 4 additions & 4 deletions gix-pack/src/cache/delta/from_offsets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ const PACK_HEADER_LEN: usize = 12;
impl<T> Tree<T> {
/// Create a new `Tree` from any data sorted by offset, ascending as returned by the `data_sorted_by_offsets` iterator.
/// * `get_pack_offset(item: &T) -> data::Offset` is a function returning the pack offset of the given item, which can be used
/// for obtaining the objects entry within the pack.
/// for obtaining the objects entry within the pack.
/// * `pack_path` is the path to the pack file itself and from which to read the entry data, which is a pack file matching the offsets
/// returned by `get_pack_offset(…)`.
/// returned by `get_pack_offset(…)`.
/// * `progress` is used to track progress when creating the tree.
/// * `resolve_in_pack_id(gix_hash::oid) -> Option<data::Offset>` takes an object ID and tries to resolve it to an object within this pack if
/// possible. Failing to do so aborts the operation, and this function is not expected to be called in usual packs. It's a theoretical
/// possibility though as old packs might have referred to their objects using the 20 bytes hash, instead of their encoded offset from the base.
/// possible. Failing to do so aborts the operation, and this function is not expected to be called in usual packs. It's a theoretical
/// possibility though as old packs might have referred to their objects using the 20 bytes hash, instead of their encoded offset from the base.
///
/// Note that the sort order is ascending. The given pack file path must match the provided offsets.
pub fn from_offsets_in_pack(
Expand Down
2 changes: 1 addition & 1 deletion gix-pack/src/data/output/entry/iter_from_counts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub(crate) mod function {
///
/// * ~~currently there is no way to easily write the pack index, even though the state here is uniquely positioned to do
/// so with minimal overhead (especially compared to `gix index-from-pack`)~~ Probably works now by chaining Iterators
/// or keeping enough state to write a pack and then generate an index with recorded data.
/// or keeping enough state to write a pack and then generate an index with recorded data.
///
pub fn iter_from_counts<Find>(
mut counts: Vec<output::Count>,
Expand Down
6 changes: 3 additions & 3 deletions gix-pack/src/index/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ impl crate::index::File {
///
/// * neither in-pack nor out-of-pack Ref Deltas are supported here, these must have been resolved beforehand.
/// * `make_resolver()` will only be called after the iterator stopped returning elements and produces a function that
/// provides all bytes belonging to a pack entry writing them to the given mutable output `Vec`.
/// It should return `None` if the entry cannot be resolved from the pack that produced the `entries` iterator, causing
/// the write operation to fail.
/// provides all bytes belonging to a pack entry writing them to the given mutable output `Vec`.
/// It should return `None` if the entry cannot be resolved from the pack that produced the `entries` iterator, causing
/// the write operation to fail.
#[allow(clippy::too_many_arguments)]
pub fn write_data_iter_to_stream<F, F2, R>(
version: crate::index::Version,
Expand Down
Loading
Loading