Skip to content

Commit

Permalink
fix: assure the correct repository is used for checkouts after clone. (
Browse files Browse the repository at this point in the history
…#1129)

If this is not the case, it's possible for filters to run in the context of
potential parent repositories, which then can have all kinds of issues.

In case of `git-lfs`, for instance, it would try to download objects
from the wrong repository.
  • Loading branch information
Byron committed Nov 25, 2023
1 parent 3b71ca5 commit 0b3eb14
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion gix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ worktree-mutation = ["attributes", "dep:gix-worktree-state"]
excludes = ["dep:gix-ignore", "dep:gix-worktree", "index"]

## Query attributes and excludes. Enables access to pathspecs, worktree checkouts, filter-pipelines and submodules.
attributes = ["excludes", "dep:gix-filter", "dep:gix-pathspec", "dep:gix-attributes", "dep:gix-submodule", "gix-worktree?/attributes"]
attributes = ["excludes", "dep:gix-filter", "dep:gix-pathspec", "dep:gix-attributes", "dep:gix-submodule", "gix-worktree?/attributes", "dep:gix-command"]

## Add support for mailmaps, as way of determining the final name of commmiters and authors.
mailmap = ["dep:gix-mailmap"]
Expand Down Expand Up @@ -254,6 +254,7 @@ gix-commitgraph = { version = "^0.22.0", path = "../gix-commitgraph" }
gix-pathspec = { version = "^0.4.0", path = "../gix-pathspec", optional = true }
gix-submodule = { version = "^0.5.0", path = "../gix-submodule", optional = true }
gix-status = { version = "^0.2.0", path = "../gix-status", optional = true }
gix-command = { version = "^0.2.10", path = "../gix-command", optional = true }

gix-worktree-stream = { version = "^0.6.0", path = "../gix-worktree-stream", optional = true }
gix-archive = { version = "^0.6.0", path = "../gix-archive", default-features = false, optional = true }
Expand Down
6 changes: 5 additions & 1 deletion gix/src/config/cache/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ impl Cache {
let capabilities = self.fs_capabilities()?;
let filters = {
let collection = Default::default();
let mut filters = gix_filter::Pipeline::new(&collection, crate::filter::Pipeline::options(repo)?);
let mut filters = gix_filter::Pipeline::new(
&collection,
repo.command_context()?,
crate::filter::Pipeline::options(repo)?,
);
if let Ok(mut head) = repo.head() {
let ctx = filters.driver_context_mut();
ctx.ref_name = head.referent_name().map(|name| name.as_bstr().to_owned());
Expand Down
38 changes: 38 additions & 0 deletions gix/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ pub mod checkout_options {
Attributes(#[from] super::attribute_stack::Error),
#[error(transparent)]
FilterPipelineOptions(#[from] crate::filter::pipeline::options::Error),
#[error(transparent)]
CommandContext(#[from] crate::config::command_context::Error),
}
}

///
#[cfg(feature = "attributes")]
pub mod command_context {
use crate::config;

/// The error produced when collecting all information relevant to spawned commands,
/// obtained via [Repository::command_context()](crate::Repository::command_context()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
PathSpec(#[from] gix_pathspec::defaults::from_environment::Error),
#[error(transparent)]
Boolean(#[from] config::boolean::Error),
}
}

Expand Down Expand Up @@ -544,3 +563,22 @@ pub(crate) struct Cache {
environment: crate::open::permissions::Environment,
// TODO: make core.precomposeUnicode available as well.
}

/// Utillities shared privately across the crate, for lack of a better place.
pub(crate) mod shared {
use crate::config;
use crate::config::cache::util::ApplyLeniency;
use crate::config::tree::Core;

pub fn is_replace_refs_enabled(
config: &gix_config::File<'static>,
lenient: bool,
mut filter_config_section: fn(&gix_config::file::Metadata) -> bool,
) -> Result<Option<bool>, config::boolean::Error> {
config
.boolean_filter_by_key("core.useReplaceRefs", &mut filter_config_section)
.map(|b| Core::USE_REPLACE_REFS.enrich_error(b))
.transpose()
.with_leniency(lenient)
}
}
8 changes: 7 additions & 1 deletion gix/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub mod pipeline {
name: BString,
source: gix_config::value::Error,
},
#[error(transparent)]
CommandContext(#[from] config::command_context::Error),
}
}

Expand Down Expand Up @@ -111,7 +113,11 @@ impl<'repo> Pipeline<'repo> {
/// Create a new instance by extracting all necessary information and configuration from a `repo` along with `cache` for accessing
/// attributes. The `index` is used for some filters which may access it under very specific circumstances.
pub fn new(repo: &'repo Repository, cache: gix_worktree::Stack) -> Result<Self, pipeline::options::Error> {
let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), Self::options(repo)?);
let pipeline = gix_filter::Pipeline::new(
cache.attributes_collection(),
repo.command_context()?,
Self::options(repo)?,
);
Ok(Pipeline {
inner: pipeline,
cache,
Expand Down
8 changes: 2 additions & 6 deletions gix/src/open/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::{Error, Options};
use crate::{
config,
config::{
cache::{interpolate_context, util::ApplyLeniency},
cache::interpolate_context,
tree::{gitoxide, Core, Key, Safe},
},
open::Permissions,
Expand Down Expand Up @@ -324,11 +324,7 @@ fn replacement_objects_refs_prefix(
lenient: bool,
mut filter_config_section: fn(&gix_config::file::Metadata) -> bool,
) -> Result<Option<PathBuf>, Error> {
let is_disabled = config
.boolean_filter_by_key("core.useReplaceRefs", &mut filter_config_section)
.map(|b| Core::USE_REPLACE_REFS.enrich_error(b))
.transpose()
.with_leniency(lenient)
let is_disabled = config::shared::is_replace_refs_enabled(config, lenient, filter_config_section)
.map_err(config::Error::ConfigBoolean)?
.unwrap_or(true);

Expand Down
20 changes: 20 additions & 0 deletions gix/src/repository/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,26 @@ impl crate::Repository {
Ok(opts)
}

/// Return the context to be passed to any spawned program that is supposed to interact with the repository, like
/// hooks or filters.
#[cfg(feature = "attributes")]
pub fn command_context(&self) -> Result<gix_command::Context, config::command_context::Error> {
Ok(gix_command::Context {
git_dir: self.git_dir().to_owned().into(),
worktree_dir: self.work_dir().map(ToOwned::to_owned),
no_replace_objects: config::shared::is_replace_refs_enabled(
&self.config.resolved,
self.config.lenient_config,
self.filter_config_section(),
)?
.map(|enabled| !enabled),
ref_namespace: None,
literal_pathspecs: None,
glob_pathspecs: None,
icase_pathspecs: None,
})
}

/// The kind of object hash the repository is configured to use.
pub fn object_hash(&self) -> gix_hash::Kind {
self.config.object_hash
Expand Down
2 changes: 2 additions & 0 deletions gix/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub mod worktree_stream {
AttributesCache(#[from] crate::config::attribute_stack::Error),
#[error(transparent)]
FilterPipeline(#[from] crate::filter::pipeline::options::Error),
#[error(transparent)]
CommandContext(#[from] crate::config::command_context::Error),
#[error("Needed {id} to be a tree to turn into a workspace stream, got {actual}")]
NotATree {
id: gix_hash::ObjectId,
Expand Down
7 changes: 5 additions & 2 deletions gix/src/repository/worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,11 @@ impl crate::Repository {
let mut cache = self
.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?
.detach();
let pipeline =
gix_filter::Pipeline::new(cache.attributes_collection(), crate::filter::Pipeline::options(self)?);
let pipeline = gix_filter::Pipeline::new(
cache.attributes_collection(),
self.command_context()?,
crate::filter::Pipeline::options(self)?,
);
let objects = self.objects.clone().into_arc().expect("TBD error handling");
let stream = gix_worktree_stream::from_tree(
id,
Expand Down

0 comments on commit 0b3eb14

Please sign in to comment.