1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use std::convert::TryInto;
use crate::Remote;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("The remote pointing to {} is anonymous and can't be saved.", url.to_bstring())]
NameMissing { url: git_url::Url },
}
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum AsError {
#[error(transparent)]
Save(#[from] Error),
#[error(transparent)]
Name(#[from] crate::remote::name::Error),
}
impl Remote<'_> {
pub fn save_to(&self, config: &mut git_config::File<'static>) -> Result<(), Error> {
let name = self.name().ok_or_else(|| Error::NameMissing {
url: self
.url
.as_ref()
.or(self.push_url.as_ref())
.expect("one url is always set")
.to_owned(),
})?;
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.into())).then(|| id))
.collect::<Vec<_>>()
}) {
let mut sections_to_remove = Vec::new();
const KEYS_TO_REMOVE: &[&str] = &["url", "pushurl", "fetch", "push"];
for id in section_ids {
let mut section = config.section_mut_by_id(id).expect("just queried");
let was_empty = section.num_values() == 0;
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 = config
.section_mut_or_create_new("remote", Some(name))
.expect("section name is validated and 'remote' is acceptable");
if let Some(url) = self.url.as_ref() {
section.push("url".try_into().expect("valid"), Some(url.to_bstring().as_ref()))
}
if let Some(url) = self.push_url.as_ref() {
section.push("pushurl".try_into().expect("valid"), Some(url.to_bstring().as_ref()))
}
for (key, spec) in self
.fetch_specs
.iter()
.map(|spec| ("fetch", spec))
.chain(self.push_specs.iter().map(|spec| ("push", spec)))
{
section.push(
key.try_into().expect("valid"),
Some(spec.to_ref().to_bstring().as_ref()),
)
}
Ok(())
}
pub fn save_as_to(
&mut self,
name: impl Into<String>,
config: &mut git_config::File<'static>,
) -> Result<(), AsError> {
let name = crate::remote::name::validated(name)?;
let prev_name = self.name.take();
self.name = name.into();
self.save_to(config).map_err(|err| {
self.name = prev_name;
err.into()
})
}
}