summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/config/tree/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/config/tree/traits.rs')
-rw-r--r--vendor/gix/src/config/tree/traits.rs199
1 files changed, 199 insertions, 0 deletions
diff --git a/vendor/gix/src/config/tree/traits.rs b/vendor/gix/src/config/tree/traits.rs
new file mode 100644
index 000000000..7cfd7aac4
--- /dev/null
+++ b/vendor/gix/src/config/tree/traits.rs
@@ -0,0 +1,199 @@
+use crate::{
+ bstr::{BStr, BString, ByteVec},
+ config::tree::key::validate_assignment,
+};
+
+/// Provide information about a configuration section.
+pub trait Section {
+ /// The section name, like `remote` in `remote.origin.url`.
+ fn name(&self) -> &str;
+ /// The keys directly underneath it for carrying configuration values.
+ fn keys(&self) -> &[&dyn Key];
+ /// The list of sub-section names, which may be empty if there are no statically known sub-sections.
+ fn sub_sections(&self) -> &[&dyn Section] {
+ &[]
+ }
+ /// The parent section if this is a statically known sub-section.
+ fn parent(&self) -> Option<&dyn Section> {
+ None
+ }
+}
+
+/// Determine how subsections may be used with a given key, suitable for obtaining the full name for use in assignments.
+#[derive(Debug, Copy, Clone)]
+pub enum SubSectionRequirement {
+ /// Subsections must not be used, this key can only be below a section.
+ Never,
+ /// The sub-section is used as parameter with the given name.
+ Parameter(&'static str),
+}
+
+/// A way to link a key with other resources.
+#[derive(Debug, Copy, Clone)]
+pub enum Link {
+ /// The environment variable of the given name will override the value of this key.
+ EnvironmentOverride(&'static str),
+ /// This config key is used as fallback if this key isn't set.
+ FallbackKey(&'static dyn Key),
+}
+
+/// A note attached to a key.
+#[derive(Debug, Copy, Clone)]
+pub enum Note {
+ /// A piece of information related to a key to help the user.
+ Informative(&'static str),
+ /// This key works differently than is described by git, explaining the deviation further.
+ Deviation(&'static str),
+}
+
+/// A leaf-level entry in the git configuration, like `url` in `remote.origin.url`.
+pub trait Key: std::fmt::Debug {
+ /// The key's name, like `url` in `remote.origin.url`.
+ fn name(&self) -> &str;
+ /// See if `value` is allowed as value of this key, or return a descriptive error if it is not.
+ fn validate(&self, value: &BStr) -> Result<(), crate::config::tree::key::validate::Error>;
+ /// The section containing this key. Git configuration has no free-standing keys, they are always underneath a section.
+ fn section(&self) -> &dyn Section;
+ /// The return value encodes three possible states to indicate subsection requirements
+ /// * `None` = subsections may or may not be used, the most flexible setting.
+ /// * `Some([Requirement][SubSectionRequirement])` = subsections must or must not be used, depending on the value
+ fn subsection_requirement(&self) -> Option<&SubSectionRequirement> {
+ Some(&SubSectionRequirement::Never)
+ }
+ /// Return the link to other resources, if available.
+ fn link(&self) -> Option<&Link> {
+ None
+ }
+ /// Return a note about this key, if available.
+ fn note(&self) -> Option<&Note> {
+ None
+ }
+
+ /// Return the name of an environment variable that would override this value (after following links until one is found).
+ fn environment_override(&self) -> Option<&str> {
+ let mut cursor = self.link()?;
+ loop {
+ match cursor {
+ Link::EnvironmentOverride(name) => return Some(name),
+ Link::FallbackKey(next) => {
+ cursor = next.link()?;
+ }
+ }
+ }
+ }
+
+ /// Return the environment override that must be set on this key.
+ /// # Panics
+ /// If no environment variable is set
+ fn the_environment_override(&self) -> &str {
+ self.environment_override()
+ .expect("BUG: environment override must be set")
+ }
+ /// Produce a name that describes how the name is composed. This is `core.bare` for statically known keys, or `branch.<name>.key`
+ /// for complex ones.
+ fn logical_name(&self) -> String {
+ let section = self.section();
+ let mut buf = String::new();
+ let parameter = if let Some(parent) = section.parent() {
+ buf.push_str(parent.name());
+ buf.push('.');
+ None
+ } else {
+ self.subsection_requirement().and_then(|requirement| match requirement {
+ SubSectionRequirement::Parameter(name) => Some(name),
+ SubSectionRequirement::Never => None,
+ })
+ };
+ buf.push_str(section.name());
+ buf.push('.');
+ if let Some(parameter) = parameter {
+ buf.push('<');
+ buf.push_str(parameter);
+ buf.push('>');
+ buf.push('.');
+ }
+ buf.push_str(self.name());
+ buf
+ }
+
+ /// The full name of the key for use in configuration overrides, like `core.bare`, or `remote.<subsection>.url` if `subsection` is
+ /// not `None`.
+ /// May fail if this key needs a subsection, or may not have a subsection.
+ fn full_name(&self, subsection: Option<&BStr>) -> Result<BString, String> {
+ let section = self.section();
+ let mut buf = BString::default();
+ let subsection = match self.subsection_requirement() {
+ None => subsection,
+ Some(requirement) => match (requirement, subsection) {
+ (SubSectionRequirement::Never, Some(_)) => {
+ return Err(format!(
+ "The key named '{}' cannot be used with non-static subsections.",
+ self.logical_name()
+ ));
+ }
+ (SubSectionRequirement::Parameter(_), None) => {
+ return Err(format!(
+ "The key named '{}' cannot be used without subsections.",
+ self.logical_name()
+ ))
+ }
+ _ => subsection,
+ },
+ };
+
+ if let Some(parent) = section.parent() {
+ buf.push_str(parent.name());
+ buf.push(b'.');
+ }
+ buf.push_str(section.name());
+ buf.push(b'.');
+ if let Some(subsection) = subsection {
+ debug_assert!(
+ section.parent().is_none(),
+ "BUG: sections with parameterized sub-sections must be top-level sections"
+ );
+ buf.push_str(subsection);
+ buf.push(b'.');
+ }
+ buf.push_str(self.name());
+ Ok(buf)
+ }
+
+ /// Return an assignment with the keys full name to `value`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this will fail if the key requires a subsection name.
+ fn validated_assignment(&self, value: &BStr) -> Result<BString, validate_assignment::Error> {
+ self.validate(value)?;
+ let mut key = self
+ .full_name(None)
+ .map_err(|message| validate_assignment::Error::Name { message })?;
+ key.push(b'=');
+ key.push_str(value);
+ Ok(key)
+ }
+
+ /// Return an assignment with the keys full name to `value`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this will fail if the key requires a subsection name.
+ fn validated_assignment_fmt(
+ &self,
+ value: &dyn std::fmt::Display,
+ ) -> Result<BString, crate::config::tree::key::validate_assignment::Error> {
+ let value = value.to_string();
+ self.validated_assignment(value.as_str().into())
+ }
+
+ /// Return an assignment to `value` with the keys full name within `subsection`, suitable for [configuration overrides][crate::open::Options::config_overrides()].
+ /// Note that this is only valid if this key supports parameterized sub-sections, or else an error is returned.
+ fn validated_assignment_with_subsection(
+ &self,
+ value: &BStr,
+ subsection: &BStr,
+ ) -> Result<BString, crate::config::tree::key::validate_assignment::Error> {
+ self.validate(value)?;
+ let mut key = self
+ .full_name(Some(subsection))
+ .map_err(|message| validate_assignment::Error::Name { message })?;
+ key.push(b'=');
+ key.push_str(value);
+ Ok(key)
+ }
+}