Skip to content

write Repository::init() config with git-config (i.e. fs capabilities) #457

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 13 commits into from
Jul 14, 2022
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
33 changes: 24 additions & 9 deletions git-config/src/file/access/comfort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ impl<'event> File<'event> {
/// Like [`value()`][File::value()], but returning an `None` if the string wasn't found.
///
/// As strings perform no conversions, this will never fail.
pub fn string(&self, section_name: &str, subsection_name: Option<&str>, key: &str) -> Option<Cow<'_, BStr>> {
pub fn string(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: impl AsRef<str>,
) -> Option<Cow<'_, BStr>> {
self.raw_value(section_name, subsection_name, key).ok()
}

Expand All @@ -22,7 +27,12 @@ impl<'event> File<'event> {
// TODO: add `secure_path()` or similar to make use of our knowledge of the trust associated with each configuration
// file, maybe even remove the insecure version to force every caller to ask themselves if the resource can
// be used securely or not.
pub fn path(&self, section_name: &str, subsection_name: Option<&str>, key: &str) -> Option<crate::Path<'_>> {
pub fn path(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: impl AsRef<str>,
) -> Option<crate::Path<'_>> {
self.raw_value(section_name, subsection_name, key)
.ok()
.map(crate::Path::from)
Expand All @@ -31,9 +41,9 @@ impl<'event> File<'event> {
/// Like [`value()`][File::value()], but returning `None` if the boolean value wasn't found.
pub fn boolean(
&self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
) -> Option<Result<bool, value::Error>> {
self.raw_value(section_name, subsection_name, key)
.ok()
Expand All @@ -43,9 +53,9 @@ impl<'event> File<'event> {
/// Like [`value()`][File::value()], but returning an `Option` if the integer wasn't found.
pub fn integer(
&self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
) -> Option<Result<i64, value::Error>> {
let int = self.raw_value(section_name, subsection_name, key).ok()?;
Some(crate::Integer::try_from(int.as_ref()).and_then(|b| {
Expand All @@ -55,17 +65,22 @@ impl<'event> File<'event> {
}

/// Similar to [`values(…)`][File::values()] but returning strings if at least one of them was found.
pub fn strings(&self, section_name: &str, subsection_name: Option<&str>, key: &str) -> Option<Vec<Cow<'_, BStr>>> {
pub fn strings(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: impl AsRef<str>,
) -> Option<Vec<Cow<'_, BStr>>> {
self.raw_values(section_name, subsection_name, key).ok()
}

/// Similar to [`values(…)`][File::values()] but returning integers if at least one of them was found
/// and if none of them overflows.
pub fn integers(
&self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
) -> Option<Result<Vec<i64>, value::Error>> {
self.raw_values(section_name, subsection_name, key).ok().map(|values| {
values
Expand Down
21 changes: 10 additions & 11 deletions git-config/src/file/access/mutate.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::borrow::Cow;

use crate::file::rename_section;
use crate::{
file::{MutableSection, SectionBody},
file::{rename_section, SectionBody, SectionMut},
lookup,
parse::section,
File,
Expand All @@ -13,15 +12,15 @@ impl<'event> File<'event> {
/// Returns an mutable section with a given name and optional subsection.
pub fn section_mut<'a>(
&'a mut self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
) -> Result<MutableSection<'a, 'event>, lookup::existing::Error> {
) -> Result<SectionMut<'a, 'event>, lookup::existing::Error> {
let id = self
.section_ids_by_name_and_subname(section_name, subsection_name)?
.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?
.rev()
.next()
.expect("BUG: Section lookup vec was empty");
Ok(MutableSection::new(
Ok(SectionMut::new(
self.sections
.get_mut(&id)
.expect("BUG: Section did not have id from lookup"),
Expand Down Expand Up @@ -53,7 +52,7 @@ impl<'event> File<'event> {
/// # use git_config::parse::section;
/// let mut git_config = git_config::File::default();
/// let mut section = git_config.new_section("hello", Some("world".into()))?;
/// section.push(section::Key::try_from("a")?, b"b".as_bstr().into());
/// section.push(section::Key::try_from("a")?, "b");
/// assert_eq!(git_config.to_string(), "[hello \"world\"]\n\ta = b\n");
/// let _section = git_config.new_section("core", None);
/// assert_eq!(git_config.to_string(), "[hello \"world\"]\n\ta = b\n[core]\n");
Expand All @@ -63,7 +62,7 @@ impl<'event> File<'event> {
&mut self,
section_name: impl Into<Cow<'event, str>>,
subsection_name: impl Into<Option<Cow<'event, str>>>,
) -> Result<MutableSection<'_, 'event>, section::header::Error> {
) -> Result<SectionMut<'_, 'event>, section::header::Error> {
let mut section = self.push_section(section_name, subsection_name, SectionBody::default())?;
section.push_newline();
Ok(section)
Expand Down Expand Up @@ -132,20 +131,20 @@ impl<'event> File<'event> {
section_name: impl Into<Cow<'event, str>>,
subsection_name: impl Into<Option<Cow<'event, str>>>,
section: SectionBody<'event>,
) -> Result<MutableSection<'_, 'event>, section::header::Error> {
) -> Result<SectionMut<'_, 'event>, section::header::Error> {
Ok(self.push_section_internal(section::Header::new(section_name, subsection_name)?, section))
}

/// Renames a section, modifying the last matching section.
pub fn rename_section<'a>(
&mut self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: impl Into<Option<&'a str>>,
new_section_name: impl Into<Cow<'event, str>>,
new_subsection_name: impl Into<Option<Cow<'event, str>>>,
) -> Result<(), rename_section::Error> {
let id = self
.section_ids_by_name_and_subname(section_name, subsection_name.into())?
.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name.into())?
.rev()
.next()
.expect("list of sections were empty, which violates invariant");
Expand Down
75 changes: 40 additions & 35 deletions git-config/src/file/access/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use std::{borrow::Cow, collections::HashMap};

use bstr::BStr;

use crate::file::mutable::value::EntryData;
use crate::{
file::{Index, MutableMultiValue, MutableSection, MutableValue, Size},
file::{mutable::multi_value::EntryData, Index, MultiValueMut, SectionMut, Size, ValueMut},
lookup,
parse::{section, Event},
File,
Expand All @@ -21,11 +20,12 @@ impl<'event> File<'event> {
/// a multivar instead.
pub fn raw_value(
&self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
) -> Result<Cow<'_, BStr>, lookup::existing::Error> {
let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?;
let key = key.as_ref();
for section_id in section_ids.rev() {
if let Some(v) = self.sections.get(&section_id).expect("known section id").value(key) {
return Ok(v);
Expand All @@ -42,12 +42,12 @@ impl<'event> File<'event> {
/// references to all values of a multivar instead.
pub fn raw_value_mut<'lookup>(
&mut self,
section_name: &'lookup str,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup str>,
key: &'lookup str,
) -> Result<MutableValue<'_, 'lookup, 'event>, lookup::existing::Error> {
) -> Result<ValueMut<'_, 'lookup, 'event>, lookup::existing::Error> {
let mut section_ids = self
.section_ids_by_name_and_subname(section_name, subsection_name)?
.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?
.rev();
let key = section::Key(Cow::<BStr>::Borrowed(key.into()));

Expand Down Expand Up @@ -88,8 +88,8 @@ impl<'event> File<'event> {
}

drop(section_ids);
return Ok(MutableValue {
section: MutableSection::new(self.sections.get_mut(&section_id).expect("known section-id")),
return Ok(ValueMut {
section: SectionMut::new(self.sections.get_mut(&section_id).expect("known section-id")),
key,
index: Index(index),
size: Size(size),
Expand Down Expand Up @@ -136,12 +136,13 @@ impl<'event> File<'event> {
/// value for a given key, if your key does not support multi-valued values.
pub fn raw_values(
&self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
) -> Result<Vec<Cow<'_, BStr>>, lookup::existing::Error> {
let mut values = Vec::new();
let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?;
let key = key.as_ref();
for section_id in section_ids {
values.extend(self.sections.get(&section_id).expect("known section id").values(key));
}
Expand Down Expand Up @@ -205,11 +206,11 @@ impl<'event> File<'event> {
/// traversal of the config.
pub fn raw_values_mut<'lookup>(
&mut self,
section_name: &'lookup str,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup str>,
key: &'lookup str,
) -> Result<MutableMultiValue<'_, 'lookup, 'event>, lookup::existing::Error> {
let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?;
) -> Result<MultiValueMut<'_, 'lookup, 'event>, lookup::existing::Error> {
let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?;
let key = section::Key(Cow::<BStr>::Borrowed(key.into()));

let mut offsets = HashMap::new();
Expand Down Expand Up @@ -255,7 +256,7 @@ impl<'event> File<'event> {
if entries.is_empty() {
Err(lookup::existing::Error::KeyMissing)
} else {
Ok(MutableMultiValue {
Ok(MultiValueMut {
section: &mut self.sections,
key,
indices_and_sizes: entries,
Expand Down Expand Up @@ -300,12 +301,12 @@ impl<'event> File<'event> {
/// ```
pub fn set_raw_value(
&mut self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
key: impl AsRef<str>,
new_value: &BStr,
) -> Result<(), lookup::existing::Error> {
self.raw_value_mut(section_name, subsection_name, key)
self.raw_value_mut(section_name, subsection_name, key.as_ref())
.map(|mut entry| entry.set(new_value))
}

Expand Down Expand Up @@ -344,9 +345,9 @@ impl<'event> File<'event> {
/// # use bstr::BStr;
/// # let mut git_config = git_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
/// let new_values = vec![
/// "x".into(),
/// "y".into(),
/// "z".into(),
/// "x",
/// "y",
/// "z",
/// ];
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
/// let fetched_config = git_config.raw_values("core", None, "a")?;
Expand All @@ -365,8 +366,8 @@ impl<'event> File<'event> {
/// # use bstr::BStr;
/// # let mut git_config = git_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
/// let new_values = vec![
/// "x".into(),
/// "y".into(),
/// "x",
/// "y",
/// ];
/// git_config.set_raw_multi_value("core", None, "a", new_values.into_iter())?;
/// let fetched_config = git_config.raw_values("core", None, "a")?;
Expand All @@ -384,23 +385,27 @@ impl<'event> File<'event> {
/// # use bstr::BStr;
/// # let mut git_config = git_config::File::try_from("[core]a=b\n[core]\na=c\na=d").unwrap();
/// let new_values = vec![
/// "x".into(),
/// "y".into(),
/// "z".into(),
/// "discarded".into(),
/// "x",
/// "y",
/// "z",
/// "discarded",
/// ];
/// git_config.set_raw_multi_value("core", None, "a", new_values)?;
/// assert!(!git_config.raw_values("core", None, "a")?.contains(&Cow::<BStr>::Borrowed("discarded".into())));
/// # Ok::<(), git_config::lookup::existing::Error>(())
/// ```
pub fn set_raw_multi_value<'a>(
pub fn set_raw_multi_value<'a, Iter, Item>(
&mut self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
key: &str,
new_values: impl IntoIterator<Item = &'a BStr>,
) -> Result<(), lookup::existing::Error> {
self.raw_values_mut(section_name, subsection_name, key)
key: impl AsRef<str>,
new_values: Iter,
) -> Result<(), lookup::existing::Error>
where
Iter: IntoIterator<Item = Item>,
Item: Into<&'a BStr>,
{
self.raw_values_mut(section_name, subsection_name, key.as_ref())
.map(|mut v| v.set_values(new_values))
}
}
4 changes: 2 additions & 2 deletions git-config/src/file/access/read_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ impl<'event> File<'event> {
/// Returns the last found immutable section with a given name and optional subsection name.
pub fn section(
&mut self,
section_name: &str,
section_name: impl AsRef<str>,
subsection_name: Option<&str>,
) -> Result<&SectionBody<'event>, lookup::existing::Error> {
let id = self
.section_ids_by_name_and_subname(section_name, subsection_name)?
.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?
.rev()
.next()
.expect("BUG: Section lookup vec was empty");
Expand Down
3 changes: 2 additions & 1 deletion git-config/src/file/access/write.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::File;
use bstr::BString;

use crate::File;

impl File<'_> {
/// Serialize this type into a `BString` for convenience.
///
Expand Down
3 changes: 1 addition & 2 deletions git-config/src/file/impls.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::str::FromStr;
use std::{convert::TryFrom, fmt::Display};
use std::{convert::TryFrom, fmt::Display, str::FromStr};

use bstr::{BStr, BString};

Expand Down
10 changes: 7 additions & 3 deletions git-config/src/file/init/from_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ use std::{borrow::Cow, path::PathBuf};

use bstr::BString;

use crate::file::from_paths;
use crate::{file::init::resolve_includes, parse::section, path::interpolate, File};
use crate::{
file::{from_paths, init::resolve_includes},
parse::section,
path::interpolate,
File,
};

/// Represents the errors that may occur when calling [`File::from_env`][crate::File::from_env()].
#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -109,7 +113,7 @@ impl File<'static> {

section.push(
section::Key(BString::from(key).into()),
git_path::into_bstr(PathBuf::from(value)).into_owned().into(),
git_path::into_bstr(PathBuf::from(value)).as_ref(),
);
}
None => {
Expand Down
10 changes: 7 additions & 3 deletions git-config/src/file/init/resolve_includes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ use std::{
use bstr::{BStr, BString, ByteSlice, ByteVec};
use git_ref::Category;

use crate::file::init::from_paths;
use crate::file::init::from_paths::Options;
use crate::{file::SectionBodyId, File};
use crate::{
file::{
init::{from_paths, from_paths::Options},
SectionBodyId,
},
File,
};

pub(crate) fn resolve_includes(
conf: &mut File<'static>,
Expand Down
Loading