Skip to content

Commit

Permalink
chore: switch from git2 to gix (#4226)
Browse files Browse the repository at this point in the history
* chore: switch from git2 to gix

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
jdx and autofix-ci[bot] authored Jan 26, 2025
1 parent cb6efa1 commit 3463ef1
Show file tree
Hide file tree
Showing 8 changed files with 1,246 additions and 214 deletions.
1,285 changes: 1,178 additions & 107 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ eyre = "0.6"
filetime = "0.2"
flate2 = "1"
fslock = "0.2.1"
git2 = "<1"
glob = "0.3"
globset = "0.4"
heck = "0.5"
Expand Down Expand Up @@ -148,6 +147,11 @@ xx = { version = "2", features = ["glob"] }
xz2 = "0.1"
zip = { version = "2", default-features = false, features = ["deflate"] }
zstd = "0.13"
gix = { version = "<1", features = [
"worktree-mutation",
"blocking-network-client",
"blocking-http-transport-reqwest",
] }

[target.'cfg(unix)'.dependencies]
exec = "0.3"
Expand Down Expand Up @@ -181,8 +185,17 @@ test-log = "0.2"

[features]
default = ["native-tls", "vfox/vendored-lua"]
native-tls = ["reqwest/native-tls", "ubi/native-tls"]
rustls = ["reqwest/rustls-tls", "self_update/rustls", "ubi/rustls-tls"]
native-tls = [
"reqwest/native-tls",
"ubi/native-tls",
"gix/blocking-http-transport-reqwest-native-tls",
]
rustls = [
"reqwest/rustls-tls",
"self_update/rustls",
"ubi/rustls-tls",
"gix/blocking-http-transport-reqwest-rust-tls",
]
rustls-native-roots = [
"reqwest/rustls-tls-native-roots",
"self_update/rustls",
Expand Down
5 changes: 5 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,11 @@
"description": "Timeout in seconds for HTTP requests to fetch new tool versions in mise.",
"type": "string"
},
"gix": {
"default": true,
"description": "Use gix for git operations, set to false to shell out to git.",
"type": "boolean"
},
"global_config_file": {
"description": "Path to the global mise config file. Default is `~/.config/mise/config.toml`. This must be an env var.",
"type": "string"
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-tarball.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $Version = ./scripts/get-version.ps1
$BaseName = "mise-v$Version-$Env:OS-$Env:ARCH"

# TODO: use "serious" feature
cargo build --release --features openssl/vendored,git2/vendored-libgit2,git2/vendored-openssl --target "$Target"
cargo build --release --features openssl/vendored --target "$Target"
mkdir -p dist/mise/bin
cp "target/$Target/release/mise.exe" dist/mise/bin/mise.exe
cp README.md dist/mise/README.md
Expand Down
6 changes: 3 additions & 3 deletions scripts/build-tarball.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ case "$os-$arch" in
esac

if command -v cross >/dev/null; then
cross build --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored,git2/vendored-libgit2,git2/vendored-openssl
cross build --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored
elif command -v zig >/dev/null; then
cargo zigbuild --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored,git2/vendored-libgit2,git2/vendored-openssl
cargo zigbuild --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored
else
cargo build --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored,git2/vendored-libgit2,git2/vendored-openssl
cargo build --profile=serious --target "$RUST_TRIPLE" --features openssl/vendored
fi
mkdir -p dist/mise/bin
mkdir -p dist/mise/man/man1
Expand Down
12 changes: 12 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,17 @@ default = "5s"
description = "Timeout in seconds for HTTP requests to fetch new tool versions in mise."
aliases = ["fetch_remote_version_timeout"]

[gix]
env = "MISE_GIX"
type = "Bool"
hide = true
default = true
description = "Use gix for git operations, set to false to shell out to git."
docs = """
Use gix for git operations. This is generally faster but may not be as compatible if the
system's gix is not the same version as the one used by mise.
"""

[global_config_file]
env = "MISE_GLOBAL_CONFIG_FILE"
type = "Path"
Expand Down Expand Up @@ -487,6 +498,7 @@ hide = true
[libgit2]
env = "MISE_LIBGIT2"
type = "Bool"
hide = true
default = true
description = "Use libgit2 for git operations, set to false to shell out to git."
docs = """
Expand Down
3 changes: 0 additions & 3 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ pub static MISE_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0));
pub static MISE_LOG_FILE: Lazy<Option<PathBuf>> = Lazy::new(|| var_path("MISE_LOG_FILE"));
pub static MISE_LOG_FILE_LEVEL: Lazy<Option<LevelFilter>> = Lazy::new(log_file_level);

pub static HTTP_PROXY: Lazy<Option<String>> =
Lazy::new(|| var("https_proxy").or_else(|_| var("http_proxy")).ok());

pub static __USAGE: Lazy<Option<String>> = Lazy::new(|| var("__USAGE").ok());

// true if running inside a shim
Expand Down
128 changes: 31 additions & 97 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::env;
use std::fmt::Debug;
use std::path::{Path, PathBuf};

use duct::Expression;
use eyre::{eyre, Result, WrapErr};
use git2::{FetchOptions, ProxyOptions};
use gix::{self};
use once_cell::sync::OnceCell;
use xx::file;

Expand All @@ -16,7 +15,7 @@ use crate::ui::progress_report::SingleReport;

pub struct Git {
pub dir: PathBuf,
pub repo: OnceCell<git2::Repository>,
pub repo: OnceCell<gix::Repository>,
}

macro_rules! git_cmd {
Expand Down Expand Up @@ -47,14 +46,10 @@ impl Git {
}
}

pub fn repo(&self) -> Result<&git2::Repository> {
pub fn repo(&self) -> Result<&gix::Repository> {
self.repo.get_or_try_init(|| {
// if !SETTINGS.libgit2 {
// trace!("libgit2 is disabled");
// return Err(eyre!("libgit2 is disabled"));
// }
trace!("opening git repository via libgit2 at {:?}", self.dir);
git2::Repository::open(&self.dir)
trace!("opening git repository via gix at {:?}", self.dir);
gix::open(&self.dir)
.wrap_err_with(|| format!("failed to open git repository at {:?}", self.dir))
.inspect_err(|err| warn!("{err:#}"))
})
Expand All @@ -64,29 +59,6 @@ impl Git {
self.dir.join(".git").is_dir()
}

// pub fn update_libgit2(
// &self,
// repo: &git2::Repository,
// gitref: &str,
// ) -> Result<(String, String)> {
// let mut fetch_options = get_fetch_options()?;
// let remote_name = "origin";
// let mut remote = repo.find_remote(remote_name)?;
// remote.fetch(&[gitref], Some(&mut fetch_options), None)?;
// let prev_rev = self.current_sha()?;
// let refname = format!("{remote_name}/{gitref}");
// let (obj, reference) = repo.revparse_ext(&refname)?;
// repo.checkout_tree(&obj, None)?;
// let commit = obj.peel_to_commit()?;
// repo.branch(gitref, &commit, true)?;
// if let Some(reference) = reference.and_then(|r| r.name().map(|s| s.to_string())) {
// repo.set_head(&reference)?;
// }
// let post_rev = self.current_sha()?;
// touch_dir(&self.dir)?;
// Ok((prev_rev, post_rev))
// }

pub fn update(&self, gitref: Option<String>) -> Result<(String, String)> {
let gitref = gitref.map_or_else(|| self.current_branch(), Ok)?;
self.update_ref(gitref, false)
Expand All @@ -98,14 +70,6 @@ impl Git {

fn update_ref(&self, gitref: String, is_tag_ref: bool) -> Result<(String, String)> {
debug!("updating {} to {}", self.dir.display(), gitref);
// if SETTINGS.libgit2 {
// if let Ok(repo) = self.repo() {
// match self.update_libgit2(repo, &gitref) {
// Ok(res) => return Ok(res),
// Err(err) => warn!("libgit2 failed: {err}"),
// }
// }
// }
let exec = |cmd: Expression| match cmd.stderr_to_stdout().stdout_capture().unchecked().run()
{
Ok(res) => {
Expand Down Expand Up @@ -157,15 +121,16 @@ impl Git {
if let Some(parent) = self.dir.parent() {
file::mkdirp(parent)?;
}
if SETTINGS.libgit2 {
if let Err(err) = git2::build::RepoBuilder::new()
.fetch_options(get_fetch_options()?)
.clone(url, &self.dir)
{
warn!("git clone failed: {err:#}");
} else {
return Ok(());
}
if SETTINGS.libgit2 || SETTINGS.gix {
let mut prepare_clone = gix::prepare_clone(url, &self.dir)?;

let (mut prepare_checkout, _) = prepare_clone
.fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;

prepare_checkout
.main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;

return Ok(());
}
match get_git_version() {
Ok(version) => trace!("git version: {}", version),
Expand All @@ -192,12 +157,11 @@ impl Git {
pub fn current_branch(&self) -> Result<String> {
let dir = &self.dir;
if let Ok(repo) = self.repo() {
let branch = repo
.head()
.wrap_err_with(|| format!("failed to get current branch in {dir:?}"))?
.shorthand()
.unwrap()
.to_string();
let head = repo.head()?;
let branch = head
.referent_name()
.map(|name| name.shorten().to_string())
.unwrap_or_else(|| head.id().unwrap().to_string());
debug!("current branch for {dir:?}: {branch}");
return Ok(branch);
}
Expand All @@ -209,8 +173,8 @@ impl Git {
let dir = &self.dir;
if let Ok(repo) = self.repo() {
let head = repo.head()?;
let head = head.peel_to_commit()?;
let sha = head.id().to_string();
let id = head.id();
let sha = id.unwrap().to_string();
debug!("current sha for {dir:?}: {sha}");
return Ok(sha);
}
Expand All @@ -223,8 +187,8 @@ impl Git {
let dir = &self.dir;
if let Ok(repo) = self.repo() {
let head = repo.head()?;
let head = head.peel_to_commit()?;
let sha = head.as_object().short_id()?.as_str().unwrap().to_string();
let id = head.id();
let sha = id.unwrap().to_string()[..7].to_string();
debug!("current sha for {dir:?}: {sha}");
return Ok(sha);
}
Expand All @@ -237,7 +201,7 @@ impl Git {
let dir = &self.dir;
if let Ok(repo) = self.repo() {
let head = repo.head()?;
let head = head.shorthand().unwrap().to_string();
let head = head.name().shorten().to_string();
debug!("current abbrev ref for {dir:?}: {head}");
return Ok(head);
}
Expand All @@ -252,10 +216,12 @@ impl Git {
return None;
}
if let Ok(repo) = self.repo() {
let remote = repo.find_remote("origin").ok()?;
let url = remote.url()?;
trace!("remote url for {dir:?}: {url}");
return Some(url.to_string());
if let Ok(remote) = repo.find_remote("origin") {
if let Some(url) = remote.url(gix::remote::Direction::Fetch) {
trace!("remote url for {dir:?}: {url}");
return Some(url.to_string());
}
}
}
let res = git_cmd_read!(&self.dir, "config", "--get", "remote.origin.url");
match res {
Expand Down Expand Up @@ -289,16 +255,6 @@ impl Git {
}
}

fn get_fetch_options() -> Result<FetchOptions<'static>> {
let mut fetch_options = FetchOptions::new();
if let Some(proxy_url) = env::HTTP_PROXY.as_ref() {
let mut proxy_options = ProxyOptions::new();
proxy_options.url(proxy_url);
fetch_options.proxy_options(proxy_options);
}
Ok(fetch_options)
}

fn get_git_version() -> Result<String> {
let version = cmd!("git", "--version").read()?;
Ok(version.trim().into())
Expand All @@ -309,25 +265,3 @@ impl Debug for Git {
f.debug_struct("Git").field("dir", &self.dir).finish()
}
}

// #[cfg(test)]
// mod tests {
// use tempfile::tempdir;
//
// use super::*;
//
// #[test]
// fn test_clone_and_update() {
// let dir = tempdir().unwrap().into_path();
// let git = Git::new(dir);
// git.clone("https://github.com/mise-plugins/rtx-tiny")
// .unwrap();
// let prev_rev = "c85ab2bea15e8b785592ce1a75db341e38ac4d33".to_string();
// let latest = git.current_sha().unwrap();
// let update_result = git.update(Some(prev_rev.clone())).unwrap();
// assert_eq!(update_result, (latest.to_string(), prev_rev.to_string()));
// assert_str_eq!(git.current_sha_short().unwrap(), "c85ab2b");
// let update_result = git.update(None).unwrap();
// assert_eq!(update_result, (prev_rev, latest));
// }
// }

0 comments on commit 3463ef1

Please sign in to comment.