summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/repository
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/gix/src/repository
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix/src/repository')
-rw-r--r--vendor/gix/src/repository/attributes.rs50
-rw-r--r--vendor/gix/src/repository/excludes.rs45
-rw-r--r--vendor/gix/src/repository/impls.rs4
-rw-r--r--vendor/gix/src/repository/init.rs3
-rw-r--r--vendor/gix/src/repository/mod.rs4
-rw-r--r--vendor/gix/src/repository/object.rs54
-rw-r--r--vendor/gix/src/repository/permissions.rs119
-rw-r--r--vendor/gix/src/repository/shallow.rs65
-rw-r--r--vendor/gix/src/repository/worktree.rs24
9 files changed, 306 insertions, 62 deletions
diff --git a/vendor/gix/src/repository/attributes.rs b/vendor/gix/src/repository/attributes.rs
new file mode 100644
index 000000000..252529761
--- /dev/null
+++ b/vendor/gix/src/repository/attributes.rs
@@ -0,0 +1,50 @@
+//! exclude information
+use crate::Repository;
+
+impl Repository {
+ /// Configure a file-system cache for accessing git attributes *and* excludes on a per-path basis.
+ ///
+ /// Use `attribute_source` to specify where to read attributes from. Also note that exclude information will
+ /// always try to read `.gitignore` files from disk before trying to read it from the `index`.
+ ///
+ /// Note that no worktree is required for this to work, even though access to in-tree `.gitattributes` and `.gitignore` files
+ /// would require a non-empty `index` that represents a git tree.
+ ///
+ /// This takes into consideration all the usual repository configuration, namely:
+ ///
+ /// * `$XDG_CONFIG_HOME/…/ignore|attributes` if `core.excludesFile|attributesFile` is *not* set, otherwise use the configured file.
+ /// * `$GIT_DIR/info/exclude|attributes` if present.
+ // TODO: test, provide higher-level custom Cache wrapper that is much easier to use and doesn't panic when accessing entries
+ // by non-relative path.
+ pub fn attributes(
+ &self,
+ index: &gix_index::State,
+ attributes_source: gix_worktree::cache::state::attributes::Source,
+ ignore_source: gix_worktree::cache::state::ignore::Source,
+ exclude_overrides: Option<gix_ignore::Search>,
+ ) -> Result<gix_worktree::Cache, crate::attributes::Error> {
+ let case = if self.config.ignore_case {
+ gix_glob::pattern::Case::Fold
+ } else {
+ gix_glob::pattern::Case::Sensitive
+ };
+ let (attributes, mut buf) = self.config.assemble_attribute_globals(
+ self.git_dir(),
+ attributes_source,
+ self.options.permissions.attributes,
+ )?;
+ let ignore =
+ self.config
+ .assemble_exclude_globals(self.git_dir(), exclude_overrides, ignore_source, &mut buf)?;
+ let state = gix_worktree::cache::State::AttributesAndIgnoreStack { attributes, ignore };
+ let attribute_list = state.id_mappings_from_index(index, index.path_backing(), ignore_source, case);
+ Ok(gix_worktree::Cache::new(
+ // this is alright as we don't cause mutation of that directory, it's virtual.
+ self.work_dir().unwrap_or(self.git_dir()),
+ state,
+ case,
+ buf,
+ attribute_list,
+ ))
+ }
+}
diff --git a/vendor/gix/src/repository/excludes.rs b/vendor/gix/src/repository/excludes.rs
new file mode 100644
index 000000000..6281549e0
--- /dev/null
+++ b/vendor/gix/src/repository/excludes.rs
@@ -0,0 +1,45 @@
+//! exclude information
+use crate::{config, Repository};
+impl Repository {
+ /// Configure a file-system cache checking if files below the repository are excluded, reading `.gitignore` files from
+ /// the specified `source`.
+ ///
+ /// Note that no worktree is required for this to work, even though access to in-tree `.gitignore` files would require
+ /// a non-empty `index` that represents a tree with `.gitignore` files.
+ ///
+ /// This takes into consideration all the usual repository configuration, namely:
+ ///
+ /// * `$XDG_CONFIG_HOME/…/ignore` if `core.excludesFile` is *not* set, otherwise use the configured file.
+ /// * `$GIT_DIR/info/exclude` if present.
+ ///
+ /// When only excludes are desired, this is the most efficient way to obtain them. Otherwise use
+ /// [`Repository::attributes()`] for accessing both attributes and excludes.
+ // TODO: test, provide higher-level custom Cache wrapper that is much easier to use and doesn't panic when accessing entries
+ // by non-relative path.
+ pub fn excludes(
+ &self,
+ index: &gix_index::State,
+ overrides: Option<gix_ignore::Search>,
+ source: gix_worktree::cache::state::ignore::Source,
+ ) -> Result<gix_worktree::Cache, config::exclude_stack::Error> {
+ let case = if self.config.ignore_case {
+ gix_glob::pattern::Case::Fold
+ } else {
+ gix_glob::pattern::Case::Sensitive
+ };
+ let mut buf = Vec::with_capacity(512);
+ let ignore = self
+ .config
+ .assemble_exclude_globals(self.git_dir(), overrides, source, &mut buf)?;
+ let state = gix_worktree::cache::State::IgnoreStack(ignore);
+ let attribute_list = state.id_mappings_from_index(index, index.path_backing(), source, case);
+ Ok(gix_worktree::Cache::new(
+ // this is alright as we don't cause mutation of that directory, it's virtual.
+ self.work_dir().unwrap_or(self.git_dir()),
+ state,
+ case,
+ buf,
+ attribute_list,
+ ))
+ }
+}
diff --git a/vendor/gix/src/repository/impls.rs b/vendor/gix/src/repository/impls.rs
index 6cf2b2e9b..5da55290c 100644
--- a/vendor/gix/src/repository/impls.rs
+++ b/vendor/gix/src/repository/impls.rs
@@ -8,6 +8,7 @@ impl Clone for crate::Repository {
self.config.clone(),
self.options.clone(),
self.index.clone(),
+ self.shallow_commits.clone(),
)
}
}
@@ -40,6 +41,7 @@ impl From<&crate::ThreadSafeRepository> for crate::Repository {
repo.config.clone(),
repo.linked_worktree_options.clone(),
repo.index.clone(),
+ repo.shallow_commits.clone(),
)
}
}
@@ -54,6 +56,7 @@ impl From<crate::ThreadSafeRepository> for crate::Repository {
repo.config,
repo.linked_worktree_options,
repo.index,
+ repo.shallow_commits,
)
}
}
@@ -68,6 +71,7 @@ impl From<crate::Repository> for crate::ThreadSafeRepository {
config: r.config,
linked_worktree_options: r.options,
index: r.index,
+ shallow_commits: r.shallow_commits,
}
}
}
diff --git a/vendor/gix/src/repository/init.rs b/vendor/gix/src/repository/init.rs
index ae6a42c3b..16659a013 100644
--- a/vendor/gix/src/repository/init.rs
+++ b/vendor/gix/src/repository/init.rs
@@ -1,6 +1,7 @@
use std::cell::RefCell;
impl crate::Repository {
+ #[allow(clippy::too_many_arguments)]
pub(crate) fn from_refs_and_objects(
refs: crate::RefStore,
objects: crate::OdbHandle,
@@ -9,6 +10,7 @@ impl crate::Repository {
config: crate::config::Cache,
linked_worktree_options: crate::open::Options,
index: crate::worktree::IndexStorage,
+ shallow_commits: crate::shallow::CommitsStorage,
) -> Self {
let objects = setup_objects(objects, &config);
crate::Repository {
@@ -20,6 +22,7 @@ impl crate::Repository {
config,
options: linked_worktree_options,
index,
+ shallow_commits,
}
}
diff --git a/vendor/gix/src/repository/mod.rs b/vendor/gix/src/repository/mod.rs
index 31199e22d..5b7a70d3b 100644
--- a/vendor/gix/src/repository/mod.rs
+++ b/vendor/gix/src/repository/mod.rs
@@ -19,17 +19,19 @@ impl crate::Repository {
}
}
+mod attributes;
mod cache;
mod config;
+mod excludes;
pub(crate) mod identity;
mod impls;
mod init;
mod location;
mod object;
-pub(crate) mod permissions;
mod reference;
mod remote;
mod revision;
+mod shallow;
mod snapshots;
mod state;
mod thread_safe;
diff --git a/vendor/gix/src/repository/object.rs b/vendor/gix/src/repository/object.rs
index bda1a54c3..f4592475f 100644
--- a/vendor/gix/src/repository/object.rs
+++ b/vendor/gix/src/repository/object.rs
@@ -1,5 +1,6 @@
#![allow(clippy::result_large_err)]
use std::convert::TryInto;
+use std::ops::DerefMut;
use gix_hash::ObjectId;
use gix_odb::{Find, FindExt, Write};
@@ -36,7 +37,7 @@ impl crate::Repository {
Ok(Object::from_data(id, kind, buf, self))
}
- /// Try to find the object with `id` or return `None` it it wasn't found.
+ /// Try to find the object with `id` or return `None` if it wasn't found.
pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {
let id = id.into();
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
@@ -58,32 +59,71 @@ impl crate::Repository {
}
}
+ fn shared_empty_buf(&self) -> std::cell::RefMut<'_, Vec<u8>> {
+ let mut bufs = self.bufs.borrow_mut();
+ if bufs.last().is_none() {
+ bufs.push(Vec::with_capacity(512));
+ }
+ std::cell::RefMut::map(bufs, |bufs| {
+ let buf = bufs.last_mut().expect("we assure one is present");
+ buf.clear();
+ buf
+ })
+ }
+
/// Write the given object into the object database and return its object id.
+ ///
+ /// Note that we hash the object in memory to avoid storing objects that are already present. That way,
+ /// we avoid writing duplicate objects using slow disks that will eventually have to be garbage collected.
pub fn write_object(&self, object: impl gix_object::WriteTo) -> Result<Id<'_>, object::write::Error> {
+ let mut buf = self.shared_empty_buf();
+ object.write_to(buf.deref_mut())?;
+
+ let oid = gix_object::compute_hash(self.object_hash(), object.kind(), &buf);
+ if self.objects.contains(oid) {
+ return Ok(oid.attach(self));
+ }
+
self.objects
- .write(object)
+ .write_buf(object.kind(), &buf)
.map(|oid| oid.attach(self))
.map_err(Into::into)
}
/// Write a blob from the given `bytes`.
+ ///
+ /// We avoid writing duplicate objects to slow disks that will eventually have to be garbage collected by
+ /// pre-hashing the data, and checking if the object is already present.
pub fn write_blob(&self, bytes: impl AsRef<[u8]>) -> Result<Id<'_>, object::write::Error> {
+ let bytes = bytes.as_ref();
+ let oid = gix_object::compute_hash(self.object_hash(), gix_object::Kind::Blob, bytes);
+ if self.objects.contains(oid) {
+ return Ok(oid.attach(self));
+ }
self.objects
- .write_buf(gix_object::Kind::Blob, bytes.as_ref())
+ .write_buf(gix_object::Kind::Blob, bytes)
.map(|oid| oid.attach(self))
}
/// Write a blob from the given `Read` implementation.
+ ///
+ /// Note that we hash the object in memory to avoid storing objects that are already present. That way,
+ /// we avoid writing duplicate objects using slow disks that will eventually have to be garbage collected.
+ ///
+ /// If that is prohibitive, use the object database directly.
pub fn write_blob_stream(
&self,
mut bytes: impl std::io::Read + std::io::Seek,
) -> Result<Id<'_>, object::write::Error> {
- let current = bytes.stream_position()?;
- let len = bytes.seek(std::io::SeekFrom::End(0))? - current;
- bytes.seek(std::io::SeekFrom::Start(current))?;
+ let mut buf = self.shared_empty_buf();
+ std::io::copy(&mut bytes, buf.deref_mut())?;
+ let oid = gix_object::compute_hash(self.object_hash(), gix_object::Kind::Blob, &buf);
+ if self.objects.contains(oid) {
+ return Ok(oid.attach(self));
+ }
self.objects
- .write_stream(gix_object::Kind::Blob, len, bytes)
+ .write_buf(gix_object::Kind::Blob, &buf)
.map(|oid| oid.attach(self))
}
diff --git a/vendor/gix/src/repository/permissions.rs b/vendor/gix/src/repository/permissions.rs
index 88b61b739..633575a9d 100644
--- a/vendor/gix/src/repository/permissions.rs
+++ b/vendor/gix/src/repository/permissions.rs
@@ -1,14 +1,7 @@
+//! Various permissions to define what can be done when operating a [`Repository`][crate::Repository].
+use crate::open::Permissions;
use gix_sec::Trust;
-/// Permissions associated with various resources of a git repository
-#[derive(Debug, Clone)]
-pub struct Permissions {
- /// Permissions related to the environment
- pub env: Environment,
- /// Permissions related to the handling of git configuration.
- pub config: Config,
-}
-
/// Configure from which sources git configuration may be loaded.
///
/// Note that configuration from inside of the repository is always loaded as it's definitely required for correctness.
@@ -17,7 +10,7 @@ pub struct Config {
/// The git binary may come with configuration as part of its configuration, and if this is true (default false)
/// we will load the configuration of the git binary, if present and not a duplicate of the ones below.
///
- /// It's disable by default as it involves executing the git binary once per execution of the application.
+ /// It's disabled by default as it may involve executing the git binary once per execution of the application.
pub git_binary: bool,
/// Whether to use the system configuration.
/// This is defined as `$(prefix)/etc/gitconfig` on unix.
@@ -50,6 +43,18 @@ impl Config {
includes: true,
}
}
+
+ /// Load only configuration local to the git repository.
+ pub fn isolated() -> Self {
+ Config {
+ git_binary: false,
+ system: false,
+ git: false,
+ user: false,
+ env: false,
+ includes: false,
+ }
+ }
}
impl Default for Config {
@@ -58,8 +63,55 @@ impl Default for Config {
}
}
+/// Configure from which `gitattribute` files may be loaded.
+///
+/// Note that `.gitattribute` files from within the repository are always loaded.
+#[derive(Copy, Clone, Ord, PartialOrd, PartialEq, Eq, Debug, Hash)]
+pub struct Attributes {
+ /// The git binary may come with attribute configuration in its installation directory, and if this is true (default false)
+ /// we will load the configuration of the git binary.
+ ///
+ /// It's disabled by default as it involves executing the git binary once per execution of the application.
+ pub git_binary: bool,
+ /// Whether to use the system configuration.
+ /// This is typically defined as `$(prefix)/etc/gitconfig`.
+ pub system: bool,
+ /// Whether to use the git application configuration.
+ ///
+ /// A platform defined location for where a user's git application configuration should be located.
+ /// If `$XDG_CONFIG_HOME` is not set or empty, `$HOME/.config/git/attributes` will be used
+ /// on unix.
+ pub git: bool,
+}
+
+impl Attributes {
+ /// Allow everything which usually relates to a fully trusted environment
+ pub fn all() -> Self {
+ Attributes {
+ git_binary: false,
+ system: true,
+ git: true,
+ }
+ }
+
+ /// Allow loading attributes that are local to the git repository.
+ pub fn isolated() -> Self {
+ Attributes {
+ git_binary: false,
+ system: false,
+ git: false,
+ }
+ }
+}
+
+impl Default for Attributes {
+ fn default() -> Self {
+ Self::all()
+ }
+}
+
/// Permissions related to the usage of environment variables
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
pub struct Environment {
/// Control whether resources pointed to by `XDG_CONFIG_HOME` can be used when looking up common configuration values.
///
@@ -101,18 +153,29 @@ impl Environment {
objects: allow,
}
}
+
+ /// Don't allow loading any environment variables.
+ pub fn isolated() -> Self {
+ let deny = gix_sec::Permission::Deny;
+ Environment {
+ xdg_config_home: deny,
+ home: deny,
+ ssh_prefix: deny,
+ git_prefix: deny,
+ http_transport: deny,
+ identity: deny,
+ objects: deny,
+ }
+ }
}
impl Permissions {
- /// Return permissions that will not include configuration files not owned by the current user,
- /// but trust system and global configuration files along with those which are owned by the current user.
- ///
- /// This allows to read and write repositories even if they aren't owned by the current user, but avoid using
- /// anything else that could cause us to write into unknown locations or use programs beyond our `PATH`.
+ /// Secure permissions are similar to `all()`
pub fn secure() -> Self {
Permissions {
env: Environment::all(),
config: Config::all(),
+ attributes: Attributes::all(),
}
}
@@ -122,32 +185,16 @@ impl Permissions {
Permissions {
env: Environment::all(),
config: Config::all(),
+ attributes: Attributes::all(),
}
}
/// Don't read any but the local git configuration and deny reading any environment variables.
pub fn isolated() -> Self {
Permissions {
- config: Config {
- git_binary: false,
- system: false,
- git: false,
- user: false,
- env: false,
- includes: false,
- },
- env: {
- let deny = gix_sec::Permission::Deny;
- Environment {
- xdg_config_home: deny,
- home: deny,
- ssh_prefix: deny,
- git_prefix: deny,
- http_transport: deny,
- identity: deny,
- objects: deny,
- }
- },
+ config: Config::isolated(),
+ attributes: Attributes::isolated(),
+ env: Environment::isolated(),
}
}
}
diff --git a/vendor/gix/src/repository/shallow.rs b/vendor/gix/src/repository/shallow.rs
new file mode 100644
index 000000000..7fac83a55
--- /dev/null
+++ b/vendor/gix/src/repository/shallow.rs
@@ -0,0 +1,65 @@
+use std::{borrow::Cow, path::PathBuf};
+
+use crate::{
+ bstr::ByteSlice,
+ config::tree::{gitoxide, Key},
+ Repository,
+};
+
+impl Repository {
+ /// Return `true` if the repository is a shallow clone, i.e. contains history only up to a certain depth.
+ pub fn is_shallow(&self) -> bool {
+ self.shallow_file()
+ .metadata()
+ .map_or(false, |m| m.is_file() && m.len() > 0)
+ }
+
+ /// Return a shared list of shallow commits which is updated automatically if the in-memory snapshot has become stale
+ /// as the underlying file on disk has changed.
+ ///
+ /// The list of shallow commits represents the shallow boundary, beyond which we are lacking all (parent) commits.
+ /// Note that the list is never empty, as `Ok(None)` is returned in that case indicating the repository
+ /// isn't a shallow clone.
+ ///
+ /// The shared list is shared across all clones of this repository.
+ pub fn shallow_commits(&self) -> Result<Option<crate::shallow::Commits>, crate::shallow::open::Error> {
+ self.shallow_commits.recent_snapshot(
+ || self.shallow_file().metadata().ok().and_then(|m| m.modified().ok()),
+ || {
+ let buf = match std::fs::read(self.shallow_file()) {
+ Ok(buf) => buf,
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
+ Err(err) => return Err(err.into()),
+ };
+
+ let mut commits = buf
+ .lines()
+ .map(gix_hash::ObjectId::from_hex)
+ .collect::<Result<Vec<_>, _>>()?;
+
+ commits.sort();
+ if commits.is_empty() {
+ Ok(None)
+ } else {
+ Ok(Some(commits))
+ }
+ },
+ )
+ }
+
+ /// Return the path to the `shallow` file which contains hashes, one per line, that describe commits that don't have their
+ /// parents within this repository.
+ ///
+ /// Note that it may not exist if the repository isn't actually shallow.
+ pub fn shallow_file(&self) -> PathBuf {
+ let shallow_name = self
+ .config
+ .resolved
+ .string_filter_by_key(
+ gitoxide::Core::SHALLOW_FILE.logical_name().as_str(),
+ &mut self.filter_config_section(),
+ )
+ .unwrap_or_else(|| Cow::Borrowed("shallow".into()));
+ self.common_dir().join(gix_path::from_bstr(shallow_name))
+ }
+}
diff --git a/vendor/gix/src/repository/worktree.rs b/vendor/gix/src/repository/worktree.rs
index 2de31bc86..316009d29 100644
--- a/vendor/gix/src/repository/worktree.rs
+++ b/vendor/gix/src/repository/worktree.rs
@@ -1,6 +1,7 @@
+use crate::config::cache::util::ApplyLeniencyDefault;
use crate::{worktree, Worktree};
-/// Worktree iteration
+/// Interact with individual worktrees and their information.
impl crate::Repository {
/// Return a list of all _linked_ worktrees sorted by private git dir path as a lightweight proxy.
///
@@ -25,10 +26,6 @@ impl crate::Repository {
res.sort_by(|a, b| a.git_dir.cmp(&b.git_dir));
Ok(res)
}
-}
-
-/// Interact with individual worktrees and their information.
-impl crate::Repository {
/// Return the repository owning the main worktree, typically from a linked worktree.
///
/// Note that it might be the one that is currently open if this repository doesn't point to a linked worktree.
@@ -58,23 +55,14 @@ impl crate::Repository {
///
/// It will use the `index.threads` configuration key to learn how many threads to use.
/// Note that it may fail if there is no index.
- // TODO: test
pub fn open_index(&self) -> Result<gix_index::File, worktree::open_index::Error> {
let thread_limit = self
.config
.resolved
- .boolean("index", None, "threads")
- .map(|res| {
- res.map(|value| usize::from(!value)).or_else(|err| {
- gix_config::Integer::try_from(err.input.as_ref())
- .map_err(|err| worktree::open_index::Error::ConfigIndexThreads {
- value: err.input.clone(),
- err,
- })
- .map(|value| value.to_decimal().and_then(|v| v.try_into().ok()).unwrap_or(1))
- })
- })
- .transpose()?;
+ .string("index", None, "threads")
+ .map(|value| crate::config::tree::Index::THREADS.try_into_index_threads(value))
+ .transpose()
+ .with_lenient_default(self.config.lenient_config)?;
gix_index::File::at(
self.index_path(),
self.object_hash(),