use std::{
io::Read,
ops::{Deref, DerefMut},
};
use gix_error::{ErrorExt, ResultExt, message};
use super::FileTransaction;
use crate::Result;
impl FileTransaction {
pub(crate) fn open(
path: std::path::PathBuf,
source: gix_config::Source,
trust: gix_sec::Trust,
lock_mode: gix_lock::acquire::Fail,
shared_repository_permissions: i32,
) -> Result<Self> {
let adjust_permissions =
|permissions| gix_fs::adjust_shared_repository_permissions(permissions, shared_repository_permissions);
let adjust_permissions: Option<&dyn Fn(std::fs::Permissions) -> std::fs::Permissions> =
(shared_repository_permissions != 0).then_some(&adjust_permissions);
let mut lock = gix_lock::File::acquire(
&path,
lock_mode,
None,
Some(&gix_lock::acquire::resolve_symlink),
adjust_permissions,
)
.or_raise(|| message("Could not acquire the lock for the configuration file"))?;
let path = lock.resource_path();
let config = match std::fs::File::open(&path) {
Ok(mut file) => {
let permissions = file
.metadata()
.or_raise(|| message!("Could not read metadata of the configuration file at {path:?}"))?
.permissions();
lock.with_mut(|file| file.set_permissions(permissions))
.or_raise(|| message!("Could not write the configuration file at {path:?}"))?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)
.or_raise(|| message!("Could not read the configuration file at {path:?}"))?;
gix_config::File::from_bytes_no_includes(
&bytes,
gix_config::file::Metadata::from(source).at(path.clone()).with(trust),
Default::default(),
)
.or_raise(|| message!("Could not parse the configuration file at {path:?}"))?
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
gix_config::File::new(gix_config::file::Metadata::from(source).at(path).with(trust))
}
Err(err) => {
return Err(err
.and_raise(message!("Could not read the configuration file at {path:?}"))
.into());
}
};
Ok(FileTransaction { lock, config })
}
pub fn commit(mut self) -> Result<()> {
let path = self.lock.resource_path();
self.config
.write_to(&mut self.lock)
.or_raise(|| message!("Could not write the configuration file at {path:?}"))?;
self.lock
.commit()
.or_raise(|| message("Could not commit the configuration file lock"))?;
Ok(())
}
}
pub(crate) fn shared_repository_permissions(
config: &gix_config::File,
filter: fn(&gix_config::file::Metadata) -> bool,
) -> Result<i32> {
let value = config.sections_by_name_and_filter("core", filter).and_then(|sections| {
sections
.filter(|section| section.header().subsection_name().is_none())
.filter_map(|section| section.value_implicit("sharedRepository"))
.last()
});
let Some(value) = value else { return Ok(0) };
crate::config::tree::Core::SHARED_REPOSITORY.try_into_shared_repository(value)
}
impl Deref for FileTransaction {
type Target = gix_config::File;
fn deref(&self) -> &Self::Target {
&self.config
}
}
impl DerefMut for FileTransaction {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.config
}
}