summaryrefslogtreecommitdiffstats
path: root/vendor/gix-submodule/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/gix-submodule/src
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-submodule/src')
-rw-r--r--vendor/gix-submodule/src/access.rs248
-rw-r--r--vendor/gix-submodule/src/config.rs216
-rw-r--r--vendor/gix-submodule/src/is_active_platform.rs49
-rw-r--r--vendor/gix-submodule/src/lib.rs144
4 files changed, 657 insertions, 0 deletions
diff --git a/vendor/gix-submodule/src/access.rs b/vendor/gix-submodule/src/access.rs
new file mode 100644
index 000000000..4def2f42f
--- /dev/null
+++ b/vendor/gix-submodule/src/access.rs
@@ -0,0 +1,248 @@
+use std::{borrow::Cow, collections::HashSet, path::Path};
+
+use bstr::BStr;
+
+use crate::{
+ config,
+ config::{Branch, FetchRecurse, Ignore, Update},
+ File, IsActivePlatform,
+};
+
+/// High-Level Access
+///
+/// Note that all methods perform validation of the requested value and report issues right away.
+/// If a bypass is needed, use [`config()`](File::config()) for direct access.
+impl File {
+ /// Return the underlying configuration file.
+ ///
+ /// Note that it might have been merged with values from another configuration file and may
+ /// thus not be accurately reflecting that state of a `.gitmodules` file anymore.
+ pub fn config(&self) -> &gix_config::File<'static> {
+ &self.config
+ }
+
+ /// Return the path at which the `.gitmodules` file lives, if it is known.
+ pub fn config_path(&self) -> Option<&Path> {
+ self.config.sections().filter_map(|s| s.meta().path.as_deref()).next()
+ }
+
+ /// Return the unvalidated names of the submodules for which configuration is present.
+ ///
+ /// Note that these exact names have to be used for querying submodule values.
+ pub fn names(&self) -> impl Iterator<Item = &BStr> {
+ let mut seen = HashSet::<&BStr>::default();
+ self.config
+ .sections_by_name("submodule")
+ .into_iter()
+ .flatten()
+ .filter_map(move |s| {
+ s.header()
+ .subsection_name()
+ .filter(|_| s.meta().source == crate::init::META_MARKER)
+ .filter(|name| seen.insert(*name))
+ })
+ }
+
+ /// Similar to [Self::is_active_platform()], but automatically applies it to each name to learn if a submodule is active or not.
+ pub fn names_and_active_state<'a>(
+ &'a self,
+ config: &'a gix_config::File<'static>,
+ defaults: gix_pathspec::Defaults,
+ attributes: &'a mut (dyn FnMut(
+ &BStr,
+ gix_pathspec::attributes::glob::pattern::Case,
+ bool,
+ &mut gix_pathspec::attributes::search::Outcome,
+ ) -> bool
+ + 'a),
+ ) -> Result<
+ impl Iterator<Item = (&BStr, Result<bool, gix_config::value::Error>)> + 'a,
+ crate::is_active_platform::Error,
+ > {
+ let mut platform = self.is_active_platform(config, defaults)?;
+ let iter = self
+ .names()
+ .map(move |name| (name, platform.is_active(config, name, attributes)));
+ Ok(iter)
+ }
+
+ /// Return a platform which allows to check if a submodule name is active or inactive.
+ /// Use `defaults` for parsing the pathspecs used to later match on names via `submodule.active` configuration retrieved from `config`.
+ ///
+ /// All `submodule.active` pathspecs are considered to be top-level specs and match the name of submodules, which are active
+ /// on inclusive match.
+ /// The full algorithm is described as [hierarchy of rules](https://git-scm.com/docs/gitsubmodules#_active_submodules).
+ pub fn is_active_platform(
+ &self,
+ config: &gix_config::File<'_>,
+ defaults: gix_pathspec::Defaults,
+ ) -> Result<IsActivePlatform, crate::is_active_platform::Error> {
+ let search = config
+ .strings_by_key("submodule.active")
+ .map(|patterns| -> Result<_, crate::is_active_platform::Error> {
+ let patterns = patterns
+ .into_iter()
+ .map(|pattern| gix_pathspec::parse(&pattern, defaults))
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(gix_pathspec::Search::from_specs(
+ patterns,
+ None,
+ std::path::Path::new(""),
+ )?)
+ })
+ .transpose()?;
+ Ok(IsActivePlatform { search })
+ }
+
+ /// Given the `relative_path` (as seen from the root of the worktree) of a submodule with possibly platform-specific
+ /// component separators, find the submodule's name associated with this path, or `None` if none was found.
+ ///
+ /// Note that this does a linear search and compares `relative_path` in a normalized form to the same form of the path
+ /// associated with the submodule.
+ pub fn name_by_path(&self, relative_path: &BStr) -> Option<&BStr> {
+ self.names()
+ .filter_map(|n| self.path(n).ok().map(|p| (n, p)))
+ .find_map(|(n, p)| (p == relative_path).then_some(n))
+ }
+}
+
+/// Per-Submodule Access
+impl File {
+ /// Return the path relative to the root directory of the working tree at which the submodule is expected to be checked out.
+ /// It's an error if the path doesn't exist as it's the only way to associate a path in the index with additional submodule
+ /// information, like the URL to fetch from.
+ ///
+ /// ### Deviation
+ ///
+ /// Git currently allows absolute paths to be used when adding submodules, but fails later as it can't find the submodule by
+ /// relative path anymore. Let's play it safe here.
+ pub fn path(&self, name: &BStr) -> Result<Cow<'_, BStr>, config::path::Error> {
+ let path_bstr =
+ self.config
+ .string("submodule", Some(name), "path")
+ .ok_or_else(|| config::path::Error::Missing {
+ submodule: name.to_owned(),
+ })?;
+ if path_bstr.is_empty() {
+ return Err(config::path::Error::Missing {
+ submodule: name.to_owned(),
+ });
+ }
+ let path = gix_path::from_bstr(path_bstr.as_ref());
+ if path.is_absolute() {
+ return Err(config::path::Error::Absolute {
+ submodule: name.to_owned(),
+ actual: path_bstr.into_owned(),
+ });
+ }
+ if gix_path::normalize(path, "".as_ref()).is_none() {
+ return Err(config::path::Error::OutsideOfWorktree {
+ submodule: name.to_owned(),
+ actual: path_bstr.into_owned(),
+ });
+ }
+ Ok(path_bstr)
+ }
+
+ /// Retrieve the `url` field of the submodule named `name`. It's an error if it doesn't exist or is empty.
+ pub fn url(&self, name: &BStr) -> Result<gix_url::Url, config::url::Error> {
+ let url = self
+ .config
+ .string("submodule", Some(name), "url")
+ .ok_or_else(|| config::url::Error::Missing {
+ submodule: name.to_owned(),
+ })?;
+
+ if url.is_empty() {
+ return Err(config::url::Error::Missing {
+ submodule: name.to_owned(),
+ });
+ }
+ gix_url::Url::from_bytes(url.as_ref()).map_err(|err| config::url::Error::Parse {
+ submodule: name.to_owned(),
+ source: err,
+ })
+ }
+
+ /// Retrieve the `update` field of the submodule named `name`, if present.
+ pub fn update(&self, name: &BStr) -> Result<Option<Update>, config::update::Error> {
+ let value: Update = match self.config.string("submodule", Some(name), "update") {
+ Some(v) => v.as_ref().try_into().map_err(|()| config::update::Error::Invalid {
+ submodule: name.to_owned(),
+ actual: v.into_owned(),
+ })?,
+ None => return Ok(None),
+ };
+
+ if let Update::Command(cmd) = &value {
+ let ours = self.config.meta();
+ let has_value_from_foreign_section = self
+ .config
+ .sections_by_name("submodule")
+ .into_iter()
+ .flatten()
+ .any(|s| (s.header().subsection_name() == Some(name) && s.meta() as *const _ != ours as *const _));
+ if !has_value_from_foreign_section {
+ return Err(config::update::Error::CommandForbiddenInModulesConfiguration {
+ submodule: name.to_owned(),
+ actual: cmd.to_owned(),
+ });
+ }
+ }
+ Ok(Some(value))
+ }
+
+ /// Retrieve the `branch` field of the submodule named `name`, or `None` if unset.
+ ///
+ /// Note that `Default` is implemented for [`Branch`].
+ pub fn branch(&self, name: &BStr) -> Result<Option<Branch>, config::branch::Error> {
+ let branch = match self.config.string("submodule", Some(name), "branch") {
+ Some(v) => v,
+ None => return Ok(None),
+ };
+
+ Branch::try_from(branch.as_ref())
+ .map(Some)
+ .map_err(|err| config::branch::Error {
+ submodule: name.to_owned(),
+ actual: branch.into_owned(),
+ source: err,
+ })
+ }
+
+ /// Retrieve the `fetchRecurseSubmodules` field of the submodule named `name`, or `None` if unset.
+ ///
+ /// Note that if it's unset, it should be retrieved from `fetch.recurseSubmodules` in the configuration.
+ pub fn fetch_recurse(&self, name: &BStr) -> Result<Option<FetchRecurse>, config::Error> {
+ self.config
+ .boolean("submodule", Some(name), "fetchRecurseSubmodules")
+ .map(FetchRecurse::new)
+ .transpose()
+ .map_err(|value| config::Error {
+ field: "fetchRecurseSubmodules",
+ submodule: name.to_owned(),
+ actual: value,
+ })
+ }
+
+ /// Retrieve the `ignore` field of the submodule named `name`, or `None` if unset.
+ pub fn ignore(&self, name: &BStr) -> Result<Option<Ignore>, config::Error> {
+ self.config
+ .string("submodule", Some(name), "ignore")
+ .map(|value| {
+ Ignore::try_from(value.as_ref()).map_err(|()| config::Error {
+ field: "ignore",
+ submodule: name.to_owned(),
+ actual: value.into_owned(),
+ })
+ })
+ .transpose()
+ }
+
+ /// Retrieve the `shallow` field of the submodule named `name`, or `None` if unset.
+ ///
+ /// If `true`, the submodule will be checked out with `depth = 1`. If unset, `false` is assumed.
+ pub fn shallow(&self, name: &BStr) -> Result<Option<bool>, gix_config::value::Error> {
+ self.config.boolean("submodule", Some(name), "shallow").transpose()
+ }
+}
diff --git a/vendor/gix-submodule/src/config.rs b/vendor/gix-submodule/src/config.rs
new file mode 100644
index 000000000..202696691
--- /dev/null
+++ b/vendor/gix-submodule/src/config.rs
@@ -0,0 +1,216 @@
+use bstr::{BStr, BString, ByteSlice};
+
+/// Determine how the submodule participates in `git status` queries. This setting also affects `git diff`.
+#[derive(Default, Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
+pub enum Ignore {
+ /// Submodule changes won't be considered at all, which is the fastest option.
+ ///
+ /// Note that changes to the submodule hash in the superproject will still be observable.
+ All,
+ /// Ignore any changes to the submodule working tree, only show committed differences between the `HEAD` of the submodule
+ /// compared to the recorded commit in the superproject.
+ Dirty,
+ /// Only ignore untracked files in the submodule, but show modifications to the submodule working tree as well as differences
+ /// between the recorded commit in the superproject and the checked-out commit in the submodule.
+ Untracked,
+ /// No modifications to the submodule are ignored, which shows untracked files, modified files in the submodule worktree as well as
+ /// differences between the recorded commit in the superproject and the checked-out commit in the submodule.
+ #[default]
+ None,
+}
+
+impl TryFrom<&BStr> for Ignore {
+ type Error = ();
+
+ fn try_from(value: &BStr) -> Result<Self, Self::Error> {
+ Ok(match value.as_bytes() {
+ b"all" => Ignore::All,
+ b"dirty" => Ignore::Dirty,
+ b"untracked" => Ignore::Untracked,
+ b"none" => Ignore::None,
+ _ => return Err(()),
+ })
+ }
+}
+
+/// Determine how to recurse into this module from the superproject when fetching.
+///
+/// Generally, a fetch is only performed if the submodule commit referenced by the superproject isn't already
+/// present in the submodule repository.
+///
+/// Note that when unspecified, the `fetch.recurseSubmodules` configuration variable should be used instead.
+#[derive(Default, Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
+pub enum FetchRecurse {
+ /// Fetch only changed submodules.
+ #[default]
+ OnDemand,
+ /// Fetch all populated submodules, changed or not.
+ ///
+ /// This skips the work needed to determine whether a submodule has changed in the first place, but may work
+ /// more as some fetches might not be necessary.
+ Always,
+ /// Submodules are never fetched.
+ Never,
+}
+
+impl FetchRecurse {
+ /// Check if `boolean` is set and translate it the respective variant, or check the underlying string
+ /// value for non-boolean options.
+ /// On error, it returns the obtained string value which would be the invalid value.
+ pub fn new(boolean: Result<bool, gix_config::value::Error>) -> Result<Self, BString> {
+ Ok(match boolean {
+ Ok(value) => {
+ if value {
+ FetchRecurse::Always
+ } else {
+ FetchRecurse::Never
+ }
+ }
+ Err(err) => {
+ if err.input != "on-demand" {
+ return Err(err.input);
+ }
+ FetchRecurse::OnDemand
+ }
+ })
+ }
+}
+
+/// Describes the branch that should be tracked on the remote.
+#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
+pub enum Branch {
+ /// The name of the remote branch should be the same as the one currently checked out in the superproject.
+ CurrentInSuperproject,
+ /// The validated remote-only branch that could be used for fetching.
+ Name(BString),
+}
+
+impl Default for Branch {
+ fn default() -> Self {
+ Branch::Name("HEAD".into())
+ }
+}
+
+impl TryFrom<&BStr> for Branch {
+ type Error = gix_refspec::parse::Error;
+
+ fn try_from(value: &BStr) -> Result<Self, Self::Error> {
+ if value == "." {
+ return Ok(Branch::CurrentInSuperproject);
+ }
+
+ gix_refspec::parse(value, gix_refspec::parse::Operation::Fetch)
+ .map(|spec| Branch::Name(spec.source().expect("no object").to_owned()))
+ }
+}
+
+/// Determine how `git submodule update` should deal with this submodule to bring it up-to-date with the
+/// super-project's expectations.
+#[derive(Default, Debug, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)]
+pub enum Update {
+ /// The commit recorded in the superproject should be checked out on a detached `HEAD`.
+ #[default]
+ Checkout,
+ /// The current branch in the submodule will be rebased onto the commit recorded in the superproject.
+ Rebase,
+ /// The commit recorded in the superproject will merged into the current branch of the submodule.
+ Merge,
+ /// A custom command to be called like `<command> hash-of-submodule-commit` that is to be executed to
+ /// perform the submodule update.
+ ///
+ /// Note that this variant is only allowed if the value is coming from an override. Thus it's not allowed to distribute
+ /// arbitrary commands via `.gitmodules` for security reasons.
+ Command(BString),
+ /// The submodule update is not performed at all.
+ None,
+}
+
+impl TryFrom<&BStr> for Update {
+ type Error = ();
+
+ fn try_from(value: &BStr) -> Result<Self, Self::Error> {
+ Ok(match value.as_bstr().as_bytes() {
+ b"checkout" => Update::Checkout,
+ b"rebase" => Update::Rebase,
+ b"merge" => Update::Merge,
+ b"none" => Update::None,
+ command if command.first() == Some(&b'!') => Update::Command(command[1..].to_owned().into()),
+ _ => return Err(()),
+ })
+ }
+}
+
+/// The error returned by [File::fetch_recurse()](crate::File::fetch_recurse) and [File::ignore()](crate::File::ignore).
+#[derive(Debug, thiserror::Error)]
+#[allow(missing_docs)]
+#[error("The '{field}' field of submodule '{submodule}' was invalid: '{actual}'")]
+pub struct Error {
+ pub field: &'static str,
+ pub submodule: BString,
+ pub actual: BString,
+}
+
+///
+pub mod branch {
+ use bstr::BString;
+
+ /// The error returned by [File::branch()](crate::File::branch).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ #[error("The value '{actual}' of the 'branch' field of submodule '{submodule}' couldn't be turned into a valid fetch refspec")]
+ pub struct Error {
+ pub submodule: BString,
+ pub actual: BString,
+ pub source: gix_refspec::parse::Error,
+ }
+}
+
+///
+pub mod update {
+ use bstr::BString;
+
+ /// The error returned by [File::update()](crate::File::update).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("The 'update' field of submodule '{submodule}' tried to set command '{actual}' to be shared")]
+ CommandForbiddenInModulesConfiguration { submodule: BString, actual: BString },
+ #[error("The 'update' field of submodule '{submodule}' was invalid: '{actual}'")]
+ Invalid { submodule: BString, actual: BString },
+ }
+}
+
+///
+pub mod url {
+ use bstr::BString;
+
+ /// The error returned by [File::url()](crate::File::url).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("The url of submodule '{submodule}' could not be parsed")]
+ Parse {
+ submodule: BString,
+ source: gix_url::parse::Error,
+ },
+ #[error("The submodule '{submodule}' was missing its 'url' field or it was empty")]
+ Missing { submodule: BString },
+ }
+}
+
+///
+pub mod path {
+ use bstr::BString;
+
+ /// The error returned by [File::path()](crate::File::path).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("The path '{actual}' of submodule '{submodule}' needs to be relative")]
+ Absolute { actual: BString, submodule: BString },
+ #[error("The submodule '{submodule}' was missing its 'path' field or it was empty")]
+ Missing { submodule: BString },
+ #[error("The path '{actual}' would lead outside of the repository worktree")]
+ OutsideOfWorktree { actual: BString, submodule: BString },
+ }
+}
diff --git a/vendor/gix-submodule/src/is_active_platform.rs b/vendor/gix-submodule/src/is_active_platform.rs
new file mode 100644
index 000000000..01d72f510
--- /dev/null
+++ b/vendor/gix-submodule/src/is_active_platform.rs
@@ -0,0 +1,49 @@
+use bstr::BStr;
+
+use crate::IsActivePlatform;
+
+/// The error returned by [File::names_and_active_state](crate::File::names_and_active_state()).
+#[derive(Debug, thiserror::Error)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error(transparent)]
+ NormalizePattern(#[from] gix_pathspec::normalize::Error),
+ #[error(transparent)]
+ ParsePattern(#[from] gix_pathspec::parse::Error),
+}
+
+impl IsActivePlatform {
+ /// Returns `true` if the submodule named `name` is active or `false` otherwise.
+ /// `config` is the configuration that was passed to the originating [modules file](crate::File).
+ /// `attributes(relative_path, case, is_dir, outcome)` provides a way to resolve the attributes mentioned
+ /// in `submodule.active` pathspecs that are evaluated in the platforms git configuration.
+ ///
+ /// A submodule's active state is determined in the following order
+ ///
+ /// * it's `submodule.<name>.active` is set in `config`
+ /// * it matches a `submodule.active` pathspec either positively or negatively via `:!<spec>`
+ /// * it's active if it has any `url` set in `config`
+ pub fn is_active(
+ &mut self,
+ config: &gix_config::File<'static>,
+ name: &BStr,
+ attributes: &mut dyn FnMut(
+ &BStr,
+ gix_pathspec::attributes::glob::pattern::Case,
+ bool,
+ &mut gix_pathspec::attributes::search::Outcome,
+ ) -> bool,
+ ) -> Result<bool, gix_config::value::Error> {
+ if let Some(val) = config.boolean("submodule", Some(name), "active").transpose()? {
+ return Ok(val);
+ };
+ if let Some(val) = self.search.as_mut().map(|search| {
+ search
+ .pattern_matching_relative_path(name, Some(true), attributes)
+ .map_or(false, |m| !m.is_excluded())
+ }) {
+ return Ok(val);
+ }
+ Ok(config.string("submodule", Some(name), "url").is_some())
+ }
+}
diff --git a/vendor/gix-submodule/src/lib.rs b/vendor/gix-submodule/src/lib.rs
new file mode 100644
index 000000000..639af30fa
--- /dev/null
+++ b/vendor/gix-submodule/src/lib.rs
@@ -0,0 +1,144 @@
+//! Primitives for describing git submodules.
+#![deny(rust_2018_idioms, missing_docs)]
+#![forbid(unsafe_code)]
+
+use std::{borrow::Cow, collections::BTreeMap};
+
+use bstr::BStr;
+
+/// All relevant information about a git module, typically from `.gitmodules` files.
+///
+/// Note that overrides from other configuration might be relevant, which is why this type
+/// can be used to take these into consideration when presented with other configuration
+/// from the superproject.
+#[derive(Clone)]
+pub struct File {
+ config: gix_config::File<'static>,
+}
+
+mod access;
+
+///
+pub mod config;
+
+///
+pub mod is_active_platform;
+
+/// A platform to keep the state necessary to perform repeated active checks, created by [File::is_active_platform()].
+pub struct IsActivePlatform {
+ pub(crate) search: Option<gix_pathspec::Search>,
+}
+
+/// Mutation
+impl File {
+ /// This can be used to let `config` override some values we know about submodules, namely…
+ ///
+ /// * `url`
+ /// * `fetchRecurseSubmodules`
+ /// * `ignore`
+ /// * `update`
+ /// * `branch`
+ ///
+ /// These values aren't validated yet, which will happen upon query.
+ pub fn append_submodule_overrides(&mut self, config: &gix_config::File<'_>) -> &mut Self {
+ let mut values = BTreeMap::<_, Vec<_>>::new();
+ for (module_name, section) in config
+ .sections_by_name("submodule")
+ .into_iter()
+ .flatten()
+ .filter_map(|s| s.header().subsection_name().map(|n| (n, s)))
+ {
+ for field in ["url", "fetchRecurseSubmodules", "ignore", "update", "branch"] {
+ if let Some(value) = section.value(field) {
+ values.entry((module_name, field)).or_default().push(value);
+ }
+ }
+ }
+
+ let values = {
+ let mut v: Vec<_> = values.into_iter().collect();
+ v.sort_by_key(|a| a.0 .0);
+ v
+ };
+
+ let mut config_to_append = gix_config::File::new(config.meta_owned());
+ let mut prev_name = None;
+ for ((module_name, field), values) in values {
+ if prev_name.map_or(true, |pn: &BStr| pn != module_name) {
+ config_to_append
+ .new_section("submodule", Some(Cow::Owned(module_name.to_owned())))
+ .expect("all names come from valid configuration, so remain valid");
+ prev_name = Some(module_name);
+ }
+ config_to_append
+ .section_mut("submodule", Some(module_name))
+ .expect("always set at this point")
+ .push(
+ field.try_into().expect("statically known key"),
+ Some(values.last().expect("at least one value or we wouldn't be here")),
+ );
+ }
+
+ self.config.append(config_to_append);
+ self
+ }
+}
+
+///
+mod init {
+ use std::path::PathBuf;
+
+ use crate::File;
+
+ impl std::fmt::Debug for File {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("File")
+ .field("config_path", &self.config_path())
+ .field("config", &format_args!("r#\"{}\"#", self.config))
+ .finish()
+ }
+ }
+
+ /// A marker we use when listing names to not pick them up from overridden sections.
+ pub(crate) const META_MARKER: gix_config::Source = gix_config::Source::Api;
+
+ /// Lifecycle
+ impl File {
+ /// Parse `bytes` as git configuration, typically from `.gitmodules`, without doing any further validation.
+ /// `path` can be provided to keep track of where the file was read from in the underlying [`config`](Self::config())
+ /// instance.
+ /// `config` is used to [apply value overrides](File::append_submodule_overrides), which can be empty if overrides
+ /// should be applied at a later time.
+ ///
+ /// Future access to the module information is lazy and configuration errors are exposed there on a per-value basis.
+ ///
+ /// ### Security Considerations
+ ///
+ /// The information itself should be used with care as it can direct the caller to fetch from remotes. It is, however,
+ /// on the caller to assure the input data can be trusted.
+ pub fn from_bytes(
+ bytes: &[u8],
+ path: impl Into<Option<PathBuf>>,
+ config: &gix_config::File<'_>,
+ ) -> Result<Self, gix_config::parse::Error> {
+ let metadata = {
+ let mut meta = gix_config::file::Metadata::from(META_MARKER);
+ meta.path = path.into();
+ meta
+ };
+ let modules = gix_config::File::from_parse_events_no_includes(
+ gix_config::parse::Events::from_bytes_owned(bytes, None)?,
+ metadata,
+ );
+
+ let mut res = Self { config: modules };
+ res.append_submodule_overrides(config);
+ Ok(res)
+ }
+
+ /// Turn ourselves into the underlying parsed configuration file.
+ pub fn into_config(self) -> gix_config::File<'static> {
+ self.config
+ }
+ }
+}