fetch_remote/
fetch_remote.rs1use std::collections::BTreeSet;
3use std::sync::atomic::AtomicBool;
4use std::time::{Duration, Instant};
5
6use girt::fetch::{FetchLimits, FetchRequest, FetchUpdateLimits, KnownHistory};
7use girt::refs::{Expected, RefName, Reflog, Target};
8use girt::remote::Remote;
9use girt::transport::TransportControl;
10use girt::{Commit, CommitFields, Config, InitKind, Repository, Signature, Tree};
11
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13 let root = tempfile::tempdir()?;
14 let source = Repository::init(
15 girt::ObjectFormat::Sha1,
16 root.path().join("source"),
17 InitKind::Bare,
18 )?;
19
20 let destination_path = root.path().join("destination");
21 let destination =
22 Repository::init(girt::ObjectFormat::Sha1, &destination_path, InitKind::Bare)?;
23
24 let objects = source.loose_objects();
25 let tree = objects.write_tree(&Tree::new(girt::ObjectFormat::Sha1, Vec::new())?)?;
26
27 let identity = Signature {
28 name: b"Fetch Example".to_vec(),
29 email: b"fetch@example.com".to_vec(),
30 seconds: 1700000000,
31 offset_minutes: 0,
32 };
33 let commit = objects.write_commit(&Commit::new(CommitFields {
34 tree,
35 parents: Vec::new(),
36 author: identity.clone(),
37 committer: identity.clone(),
38 extra_headers: Vec::new(),
39 message: b"Original fetch example\n".to_vec(),
40 })?)?;
41
42 source.references()?.update_without_reflog(
43 &RefName::new("refs/heads/main")?,
44 Target::Direct(commit),
45 Expected::Absent,
46 )?;
47
48 let config = Config::parse(
51 b"[remote \"origin\"]\nurl = local-example\nfetch = +refs/heads/*:refs/remotes/origin/*\n",
52 )?;
53
54 let remote = Remote::find(&config, b"origin")?.ok_or("missing remote")?;
55 assert_eq!(remote.fetch_url(), Some(b"local-example".as_slice()));
56
57 let request = FetchRequest::prepare(
60 destination,
61 remote.fetch_refspecs().clone(),
62 BTreeSet::new(),
63 Reflog::Append {
64 committer: identity,
65 message: b"fetch origin".to_vec(),
66 },
67 )?;
68
69 let cancel = AtomicBool::new(false);
70 let control = TransportControl::new(&cancel)
71 .with_deadline(Some(Instant::now() + Duration::from_secs(30)));
72 let ready = request.receive_local(
73 source.git_dir(),
74 &KnownHistory::default(),
75 FetchLimits::default(),
76 control,
77 girt::fetch::LocalFetchObserver::default(),
78 )?;
79
80 let report = match ready.finish(FetchUpdateLimits::default(), &cancel) {
81 Ok(report) => report,
82 Err(error) => {
83 eprintln!(
86 "Fetch effects: {:?}; failure: {}",
87 error.report, error.source
88 );
89 return Err(error.into());
90 }
91 };
92
93 let destination = Repository::open(&destination_path)?;
94 assert_eq!(
95 destination
96 .references()?
97 .read(&RefName::new("refs/remotes/origin/main")?)?,
98 Some(Target::Direct(commit))
99 );
100 assert!(!destination.git_dir().join("FETCH_HEAD").exists());
101
102 println!(
103 "Validated {} objects, installed {:?}, published {} reference(s)",
104 report.objects,
105 report.installed,
106 report.references.len()
107 );
108
109 Ok(())
111}