use crate::{Error, Remote, Result, bstr::BStr, config, remote};
use gix_utils::AsBStr;
impl Remote<'_> {
pub fn save_to(&self, config: &mut gix_config::File) -> Result<()> {
let name = self.name().ok_or_else(|| {
let url = self
.urls
.first()
.or_else(|| self.push_urls.first())
.expect("one url is always set")
.to_bstring();
Error::from_error(gix_error::message!(
"The remote pointing to {url} is anonymous and can't be saved."
))
})?;
let target_meta = config.meta().clone();
let mut needs_url_reset = false;
let mut needs_push_url_reset = false;
if let Some(section_ids) = config.sections_and_ids_by_name("remote").map(|it| {
it.filter_map(|(s, id)| (s.header().subsection_name() == Some(name.as_bstr())).then_some(id))
.collect::<Vec<_>>()
}) {
let mut sections_to_remove = Vec::new();
const KEYS_TO_REMOVE: &[&str] = &[
config::tree::Remote::URL.name,
config::tree::Remote::PUSH_URL.name,
config::tree::Remote::FETCH.name,
config::tree::Remote::PUSH.name,
config::tree::Remote::TAG_OPT.name,
];
for id in section_ids {
let mut section = config.section_mut_by_id(id).expect("just queried");
let was_empty = section.num_values() == 0;
let url_values = section.values(config::tree::Remote::URL.name);
let push_url_values = section.values(config::tree::Remote::PUSH_URL.name);
if *section.meta() != target_meta {
needs_url_reset |= !url_values.is_empty();
needs_push_url_reset |= !push_url_values.is_empty();
} else {
needs_url_reset |= url_values.iter().any(|url| url.is_empty());
needs_push_url_reset |= push_url_values.iter().any(|url| url.is_empty());
}
for key in KEYS_TO_REMOVE {
while section.remove(key).is_some() {}
}
let is_empty_after_deletions_of_values_to_be_written = section.num_values() == 0;
if !was_empty && is_empty_after_deletions_of_values_to_be_written {
sections_to_remove.push(id);
}
}
for id in sections_to_remove {
config.remove_section_by_id(id);
}
}
let mut section = if needs_url_reset || needs_push_url_reset {
config
.new_section("remote", name.as_bstr())
.expect("section name is validated and 'remote' is acceptable")
} else {
config
.section_mut_or_create_new_filter("remote", name.as_bstr(), |meta| *meta == target_meta)
.expect("section name is validated and 'remote' is acceptable")
};
if needs_url_reset {
section.push(config::tree::Remote::URL.name, "")?;
}
for url in &self.urls {
section.push("url", url.to_bstring())?;
}
if needs_push_url_reset {
section.push(config::tree::Remote::PUSH_URL.name, "")?;
}
for url in &self.push_urls {
section.push("pushurl", url.to_bstring())?;
}
if self.fetch_tags != Default::default() {
section.push(
config::tree::Remote::TAG_OPT.name,
BStr::new(match self.fetch_tags {
remote::fetch::Tags::All => "--tags",
remote::fetch::Tags::None => "--no-tags",
remote::fetch::Tags::Included => {
unreachable!("BUG: the default shouldn't be written and we try")
}
}),
)?;
}
for (key, spec) in self
.fetch_specs
.iter()
.map(|spec| ("fetch", spec))
.chain(self.push_specs.iter().map(|spec| ("push", spec)))
{
section.push(key, spec.to_ref().to_bstring())?;
}
Ok(())
}
pub fn save_as_to(&mut self, name: impl AsBStr, config: &mut gix_config::File) -> Result<()> {
let name = crate::remote::name::validated(name.as_bstr().to_owned())?;
let prev_name = self.name.take();
self.name = Some(name.into());
self.save_to(config).inspect_err(|_| {
self.name = prev_name;
})
}
}