Skip to content

Commit 728f688

Browse files
committed
refactor (#450)
1 parent 2c9edff commit 728f688

File tree

1 file changed

+127
-121
lines changed

1 file changed

+127
-121
lines changed

git-repository/src/clone/fetch.rs

Lines changed: 127 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -51,125 +51,8 @@ impl PrepareFetch {
5151
P: crate::Progress,
5252
P::SubProgress: 'static,
5353
{
54-
use crate::bstr::{BStr, ByteVec};
54+
use crate::bstr::ByteVec;
5555
use crate::remote::fetch::RefLogMessage;
56-
use git_ref::transaction::{LogChange, RefLog};
57-
58-
fn write_remote_to_local_config_file(
59-
remote: &mut crate::Remote<'_>,
60-
remote_name: String,
61-
) -> Result<git_config::File<'static>, Error> {
62-
let mut metadata = git_config::file::Metadata::from(git_config::Source::Local);
63-
let config_path = remote.repo.git_dir().join("config");
64-
metadata.path = Some(config_path.clone());
65-
let mut config =
66-
git_config::File::from_paths_metadata(Some(metadata), Default::default())?.expect("one file to load");
67-
remote.save_as_to(remote_name, &mut config)?;
68-
std::fs::write(config_path, config.to_bstring())?;
69-
Ok(config)
70-
}
71-
72-
fn replace_changed_local_config_file(repo: &mut Repository, mut config: git_config::File<'static>) {
73-
let repo_config = git_features::threading::OwnShared::make_mut(&mut repo.config.resolved);
74-
let ids_to_remove: Vec<_> = repo_config
75-
.sections_and_ids()
76-
.filter_map(|(s, id)| {
77-
matches!(s.meta().source, git_config::Source::Local | git_config::Source::Api).then(|| id)
78-
})
79-
.collect();
80-
for id in ids_to_remove {
81-
repo_config.remove_section_by_id(id);
82-
}
83-
crate::config::overrides::apply(&mut config, &repo.options.config_overrides, git_config::Source::Api)
84-
.expect("applied once and can be applied again");
85-
repo_config.append(config);
86-
repo.reread_values_and_clear_caches()
87-
.expect("values could be read once and can be read again");
88-
}
89-
90-
/// HEAD cannot be written by means of refspec by design, so we have to do it manually here. Also create the pointed-to ref
91-
/// if we have to, as it might not have been naturally included in the ref-specs.
92-
fn update_head(
93-
repo: &Repository,
94-
remote_refs: &[git_protocol::fetch::Ref],
95-
reflog_message: &BStr,
96-
) -> Result<(), Error> {
97-
use git_ref::transaction::{PreviousValue, RefEdit};
98-
use git_ref::Target;
99-
use std::convert::TryInto;
100-
let (head_peeled_id, head_ref) = match remote_refs.iter().find_map(|r| match r {
101-
git_protocol::fetch::Ref::Symbolic {
102-
full_ref_name,
103-
target,
104-
object,
105-
} if full_ref_name == "HEAD" => Some((object, Some(target))),
106-
git_protocol::fetch::Ref::Direct { full_ref_name, object } if full_ref_name == "HEAD" => {
107-
Some((object, None))
108-
}
109-
_ => None,
110-
}) {
111-
Some(t) => t,
112-
None => return Ok(()),
113-
};
114-
115-
let name: git_ref::FullName = "HEAD".try_into().expect("valid");
116-
let reflog_message = || LogChange {
117-
mode: RefLog::AndReference,
118-
force_create_reflog: false,
119-
message: reflog_message.to_owned(),
120-
};
121-
match head_ref {
122-
Some(referent) => {
123-
let referent: git_ref::FullName = referent.try_into().map_err(|err| Error::InvalidHeadRef {
124-
head_ref_name: referent.to_owned(),
125-
source: err,
126-
})?;
127-
repo.edit_references([
128-
RefEdit {
129-
change: git_ref::transaction::Change::Update {
130-
log: reflog_message(),
131-
expected: PreviousValue::Any,
132-
new: Target::Peeled(head_peeled_id.to_owned()),
133-
},
134-
name: referent.clone(),
135-
deref: false,
136-
},
137-
RefEdit {
138-
change: git_ref::transaction::Change::Update {
139-
log: reflog_message(),
140-
expected: PreviousValue::Any,
141-
new: Target::Symbolic(referent),
142-
},
143-
name: name.clone(),
144-
deref: false,
145-
},
146-
])?;
147-
let mut log = reflog_message();
148-
log.mode = RefLog::Only;
149-
repo.edit_reference(RefEdit {
150-
change: git_ref::transaction::Change::Update {
151-
log,
152-
expected: PreviousValue::Any,
153-
new: Target::Peeled(head_peeled_id.to_owned()),
154-
},
155-
name,
156-
deref: false,
157-
})?;
158-
}
159-
None => {
160-
repo.edit_reference(RefEdit {
161-
change: git_ref::transaction::Change::Update {
162-
log: reflog_message(),
163-
expected: PreviousValue::Any,
164-
new: Target::Peeled(head_peeled_id.to_owned()),
165-
},
166-
name,
167-
deref: false,
168-
})?;
169-
}
170-
};
171-
Ok(())
172-
}
17356

17457
let repo = self
17558
.repo
@@ -197,7 +80,7 @@ impl PrepareFetch {
19780
remote = f(remote)?;
19881
}
19982

200-
let config = write_remote_to_local_config_file(&mut remote, remote_name.clone())?;
83+
let config = util::write_remote_to_local_config_file(&mut remote, remote_name.clone())?;
20184

20285
// Add HEAD after the remote was written to config, we need it to know what to checkout later, and assure
20386
// the ref that HEAD points to is present no matter what.
@@ -226,8 +109,8 @@ impl PrepareFetch {
226109
})
227110
.receive(should_interrupt)?;
228111

229-
replace_changed_local_config_file(repo, config);
230-
update_head(repo, &outcome.ref_map.remote_refs, reflog_message.as_ref())?;
112+
util::replace_changed_local_config_file(repo, config);
113+
util::update_head(repo, &outcome.ref_map.remote_refs, reflog_message.as_ref())?;
231114

232115
Ok((self.repo.take().expect("still present"), outcome))
233116
}
@@ -300,3 +183,126 @@ impl From<PrepareFetch> for Repository {
300183
prep.persist()
301184
}
302185
}
186+
187+
mod util {
188+
use super::Error;
189+
use crate::bstr::BStr;
190+
use crate::Repository;
191+
use git_ref::transaction::{LogChange, RefLog};
192+
193+
pub fn write_remote_to_local_config_file(
194+
remote: &mut crate::Remote<'_>,
195+
remote_name: String,
196+
) -> Result<git_config::File<'static>, Error> {
197+
let mut metadata = git_config::file::Metadata::from(git_config::Source::Local);
198+
let config_path = remote.repo.git_dir().join("config");
199+
metadata.path = Some(config_path.clone());
200+
let mut config =
201+
git_config::File::from_paths_metadata(Some(metadata), Default::default())?.expect("one file to load");
202+
remote.save_as_to(remote_name, &mut config)?;
203+
std::fs::write(config_path, config.to_bstring())?;
204+
Ok(config)
205+
}
206+
207+
pub fn replace_changed_local_config_file(repo: &mut Repository, mut config: git_config::File<'static>) {
208+
let repo_config = git_features::threading::OwnShared::make_mut(&mut repo.config.resolved);
209+
let ids_to_remove: Vec<_> = repo_config
210+
.sections_and_ids()
211+
.filter_map(|(s, id)| {
212+
matches!(s.meta().source, git_config::Source::Local | git_config::Source::Api).then(|| id)
213+
})
214+
.collect();
215+
for id in ids_to_remove {
216+
repo_config.remove_section_by_id(id);
217+
}
218+
crate::config::overrides::apply(&mut config, &repo.options.config_overrides, git_config::Source::Api)
219+
.expect("applied once and can be applied again");
220+
repo_config.append(config);
221+
repo.reread_values_and_clear_caches()
222+
.expect("values could be read once and can be read again");
223+
}
224+
225+
/// HEAD cannot be written by means of refspec by design, so we have to do it manually here. Also create the pointed-to ref
226+
/// if we have to, as it might not have been naturally included in the ref-specs.
227+
pub fn update_head(
228+
repo: &Repository,
229+
remote_refs: &[git_protocol::fetch::Ref],
230+
reflog_message: &BStr,
231+
) -> Result<(), Error> {
232+
use git_ref::transaction::{PreviousValue, RefEdit};
233+
use git_ref::Target;
234+
use std::convert::TryInto;
235+
let (head_peeled_id, head_ref) = match remote_refs.iter().find_map(|r| match r {
236+
git_protocol::fetch::Ref::Symbolic {
237+
full_ref_name,
238+
target,
239+
object,
240+
} if full_ref_name == "HEAD" => Some((object, Some(target))),
241+
git_protocol::fetch::Ref::Direct { full_ref_name, object } if full_ref_name == "HEAD" => {
242+
Some((object, None))
243+
}
244+
_ => None,
245+
}) {
246+
Some(t) => t,
247+
None => return Ok(()),
248+
};
249+
250+
let name: git_ref::FullName = "HEAD".try_into().expect("valid");
251+
let reflog_message = || LogChange {
252+
mode: RefLog::AndReference,
253+
force_create_reflog: false,
254+
message: reflog_message.to_owned(),
255+
};
256+
match head_ref {
257+
Some(referent) => {
258+
let referent: git_ref::FullName = referent.try_into().map_err(|err| Error::InvalidHeadRef {
259+
head_ref_name: referent.to_owned(),
260+
source: err,
261+
})?;
262+
repo.edit_references([
263+
RefEdit {
264+
change: git_ref::transaction::Change::Update {
265+
log: reflog_message(),
266+
expected: PreviousValue::Any,
267+
new: Target::Peeled(head_peeled_id.to_owned()),
268+
},
269+
name: referent.clone(),
270+
deref: false,
271+
},
272+
RefEdit {
273+
change: git_ref::transaction::Change::Update {
274+
log: reflog_message(),
275+
expected: PreviousValue::Any,
276+
new: Target::Symbolic(referent),
277+
},
278+
name: name.clone(),
279+
deref: false,
280+
},
281+
])?;
282+
let mut log = reflog_message();
283+
log.mode = RefLog::Only;
284+
repo.edit_reference(RefEdit {
285+
change: git_ref::transaction::Change::Update {
286+
log,
287+
expected: PreviousValue::Any,
288+
new: Target::Peeled(head_peeled_id.to_owned()),
289+
},
290+
name,
291+
deref: false,
292+
})?;
293+
}
294+
None => {
295+
repo.edit_reference(RefEdit {
296+
change: git_ref::transaction::Change::Update {
297+
log: reflog_message(),
298+
expected: PreviousValue::Any,
299+
new: Target::Peeled(head_peeled_id.to_owned()),
300+
},
301+
name,
302+
deref: false,
303+
})?;
304+
}
305+
};
306+
Ok(())
307+
}
308+
}

0 commit comments

Comments
 (0)