fe_common/utils/
git.rs

1#[cfg(not(target_arch = "wasm32"))]
2use git2::{FetchOptions, Oid, Repository};
3use std::error::Error;
4#[cfg(not(target_arch = "wasm32"))]
5use std::path::Path;
6
7/// Fetch and checkout the specified refspec from the remote repository without
8/// fetching any additional history.
9#[cfg(not(target_arch = "wasm32"))]
10pub fn fetch_and_checkout<P: AsRef<Path>>(
11    remote: &str,
12    target_directory: P,
13    refspec: &str,
14) -> Result<(), Box<dyn Error>> {
15    // We initialize the repo here so that we can be sure that we created a directory that
16    // needs to be clean up in case of an error. If the init fails, there won't be anything
17    // to clean up.
18    let repo = Repository::init(&target_directory)?;
19    let res = _fetch_and_checkout(remote, repo, refspec);
20    if res.is_err() {
21        std::fs::remove_dir_all(target_directory).expect("Failed to clean up directory");
22    }
23
24    res
25}
26
27#[cfg(not(target_arch = "wasm32"))]
28fn _fetch_and_checkout(
29    remote: &str,
30    repo: Repository,
31    refspec: &str,
32) -> Result<(), Box<dyn Error>> {
33    let mut remote = repo.remote("origin", remote)?;
34
35    let mut fetch_options = FetchOptions::new();
36
37    fetch_options.depth(1);
38
39    // Fetch the specified SHA1 with depth 1
40    if let Err(e) = remote.fetch(&[refspec], Some(&mut fetch_options), None) {
41        if let (git2::ErrorClass::Net, git2::ErrorCode::GenericError) = (e.class(), e.code()) {
42            // That's a pretty cryptic error for the common case of the refspec not existing.
43            // We keep the cryptic error (because it might have other causes) but add a hint.
44            return Err(format!("{}\nMake sure revision {} exists in remote", e, refspec).into());
45        } else {
46            return Err(e.into());
47        }
48    }
49
50    // Find the fetched commit by SHA1
51    let oid = Oid::from_str(refspec)?;
52    let commit = repo.find_commit(oid)?;
53
54    // Checkout the commit
55    repo.checkout_tree(commit.as_object(), None)?;
56    repo.set_head_detached(oid)?;
57
58    Ok(())
59}
60
61#[cfg(target_arch = "wasm32")]
62pub fn fetch_and_checkout(
63    _remote: &str,
64    _target_directory: &str,
65    _refspec: &str,
66) -> Result<(), Box<dyn Error>> {
67    Err("Not supported on WASM".into())
68}