migrating from git2 to gitoxide crate for git downloads

This commit is contained in:
Stefano Fontana 2024-12-15 18:30:39 +01:00
parent a295495dc5
commit 3962be8ebf
4 changed files with 1128 additions and 119 deletions

1182
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,6 @@ typst-timing = { path = "crates/typst-timing", version = "0.12.0" }
typst-utils = { path = "crates/typst-utils", version = "0.12.0" }
typst-assets = { git = "https://github.com/typst/typst-assets", rev = "8cccef9" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "b07d156" }
auth-git2 = "0.5.5"
arrayvec = "0.7.4"
az = "1.2"
base64 = "0.22"
@ -59,7 +58,7 @@ env_proxy = "0.4"
flate2 = "1"
fontdb = { version = "0.21", default-features = false }
fs_extra = "1.3"
git2 = "0.19.0"
gix = "0.68.0"
hayagriva = "0.8"
heck = "0.5"
hypher = "0.1.4"

View File

@ -25,8 +25,7 @@ native-tls = { workspace = true, optional = true }
once_cell = { workspace = true }
tar = { workspace = true, optional = true }
ureq = { workspace = true, optional = true }
git2 = { workspace = true, optional = true }
auth-git2 = { workspace = true, optional = true }
gix = { workspace = true, optional = true, features = ["worktree-mutation", "blocking-network-client"] }
# Explicitly depend on OpenSSL if applicable, so that we can add the
# `openssl/vendored` feature to it if `vendor-openssl` is enabled.
@ -42,7 +41,7 @@ fonts = ["dep:fontdb", "fontdb/memmap", "fontdb/fontconfig"]
# Add generic downloading utilities
downloads = ["downloads_http", "downloads_git"]
downloads_http = ["dep:env_proxy", "dep:native-tls", "dep:ureq", "dep:openssl"]
downloads_git = ["git2", "auth-git2"]
downloads_git = ["gix"]
# Add package downloading utilities, implies `downloads`
packages = ["downloads", "dep:dirs", "dep:flate2", "dep:tar"]

View File

@ -1,10 +1,8 @@
use crate::package_downloads::{DownloadState, PackageDownloader, Progress};
use auth_git2::GitAuthenticator;
use ecow::{eco_format, EcoString};
use git2::build::RepoBuilder;
use git2::{FetchOptions, RemoteCallbacks};
use std::collections::VecDeque;
use gix::remote::fetch::Shallow;
use std::fmt::Debug;
use std::num::NonZero;
use std::path::Path;
use std::time::Instant;
use typst_library::diag::{PackageError, PackageResult};
@ -32,45 +30,34 @@ impl GitDownloader {
progress: &mut dyn Progress,
) -> Result<(), EcoString> {
progress.print_start();
eprintln!("{} {} {}", repo, tag, dest.display());
let state = DownloadState {
content_len: None,
total_downloaded: 0,
bytes_per_second: VecDeque::from(vec![0; 5]),
bytes_per_second: Default::default(),
start_time: Instant::now(),
};
let auth = GitAuthenticator::default();
let git_config = git2::Config::open_default()
.map_err(|err| EcoString::from(format!("{err}")))?;
std::fs::create_dir_all(dest).map_err(|x| eco_format!("{x}"))?;
let url = gix::url::parse(repo.into()).map_err(|x| eco_format!("{x}"))?;
let mut prepare_fetch =
gix::prepare_clone(url, dest).map_err(|x| eco_format!("{x}"))?;
prepare_fetch = prepare_fetch
.with_shallow(Shallow::DepthAtRemote(NonZero::new(1).unwrap()))
.with_ref_name(Some(tag))
.map_err(|x| eco_format!("{x}"))?;
let mut fetch_options = FetchOptions::new();
let mut remote_callbacks = RemoteCallbacks::new();
remote_callbacks.credentials(auth.credentials(&git_config));
fetch_options.remote_callbacks(remote_callbacks);
let repo = RepoBuilder::new()
.fetch_options(fetch_options)
.clone(repo, dest)
.map_err(|err| EcoString::from(format!("{err}")))?;
let (object, reference) = repo
.revparse_ext(tag)
.map_err(|err| EcoString::from(format!("{err}")))?;
repo.checkout_tree(&object, None)
.map_err(|err| EcoString::from(format!("{err}")))?;
match reference {
// gref is an actual reference like branches or tags
Some(gref) => repo.set_head(gref.name().unwrap()),
// this is a commit, not a reference
None => repo.set_head_detached(object.id()),
let (mut prepare_checkout, _) = prepare_fetch
.fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)
.map_err(|x| eco_format!("{x}"))?;
if prepare_checkout.repo().work_dir().is_none() {
return Err(eco_format!(
"Cloned git repository but files are not available."
))?;
}
.map_err(|err| EcoString::from(format!("{err}")))?;
prepare_checkout
.main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)
.map_err(|x| eco_format!("{x}"))?;
progress.print_finish(&state);
Ok(())
}
@ -122,7 +109,7 @@ impl PackageDownloader for GitDownloader {
) -> PackageResult<()> {
let repo = Self::parse_namespace(spec.namespace.as_str(), spec.name.as_str())
.map_err(|x| PackageError::Other(Some(x)))?;
let tag = format!("v{}", spec.version);
let tag = format!("refs/tags/v{}", spec.version);
self.download_with_progress(repo.as_str(), tag.as_str(), package_dir, progress)
.map_err(|x| PackageError::Other(Some(x)))
}