mirror of
https://github.com/msfjarvis/gitice
synced 2025-08-14 22:07:00 +05:30
feat(git): switch to gitoxide for freeze command
This commit is contained in:
parent
b37ede3442
commit
5372360c1c
5 changed files with 1256 additions and 114 deletions
1239
Cargo.lock
generated
1239
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -16,7 +16,7 @@ include = ["src/**/*", "LICENSE-*", "README.md"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
clap = { version = "4.2.7", features = [ "color", "deprecated", "derive" ] }
|
clap = { version = "4.2.7", features = [ "color", "deprecated", "derive" ] }
|
||||||
git2 = { version = "0.17.1", default-features = false, features = ["vendored-libgit2", "vendored-openssl"] }
|
gix = "0.44.1"
|
||||||
serde = { version = "1.0.162", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.162", default-features = false, features = ["derive"] }
|
||||||
serde_derive = "1.0.162"
|
serde_derive = "1.0.162"
|
||||||
toml = "0.7.3"
|
toml = "0.7.3"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "stable"
|
channel = "nightly-2023-02-22"
|
||||||
components = [ "clippy", "rustfmt", "rust-src" ]
|
components = [ "clippy", "rustfmt", "rust-src" ]
|
||||||
targets = [ "x86_64-unknown-linux-gnu" ]
|
targets = [ "x86_64-unknown-linux-gnu" ]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|
114
src/git.rs
114
src/git.rs
|
@ -1,5 +1,5 @@
|
||||||
use crate::model::PersistableRepo;
|
use crate::model::PersistableRepo;
|
||||||
use git2::Repository;
|
use gix::{sec::trust::DefaultForLevel, Repository, ThreadSafeRepository};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs,
|
fs,
|
||||||
|
@ -17,42 +17,63 @@ pub(crate) fn freeze_repos(dir: &str) -> anyhow::Result<()> {
|
||||||
if entry.file_type().is_dir() {
|
if entry.file_type().is_dir() {
|
||||||
let path = format!("{}/.git", entry.path().display());
|
let path = format!("{}/.git", entry.path().display());
|
||||||
let git_dir = Path::new(&path);
|
let git_dir = Path::new(&path);
|
||||||
|
if git_dir.exists() && git_dir.is_dir() {
|
||||||
|
let mut git_open_opts_map =
|
||||||
|
gix::sec::trust::Mapping::<gix::open::Options>::default();
|
||||||
|
|
||||||
if git_dir.exists() {
|
// don't use the global git configs
|
||||||
let repo = Repository::open(git_dir)?;
|
let config = gix::open::permissions::Config {
|
||||||
if repo.is_empty()? {
|
git_binary: false,
|
||||||
continue;
|
system: false,
|
||||||
}
|
git: false,
|
||||||
|
user: false,
|
||||||
let head = repo.head()?;
|
env: true,
|
||||||
if let Some(head) = head.name() {
|
includes: true,
|
||||||
if let Ok(upstream) = repo.branch_upstream_name(head) {
|
};
|
||||||
if let Ok(remote) = repo.find_remote(
|
// change options for config permissions without touching anything else
|
||||||
// This is a rather ugly hack, but not sure how else to get the required name
|
git_open_opts_map.reduced =
|
||||||
// doesn't seem to work with the full name such as `refs/remotes/origin/master`
|
git_open_opts_map
|
||||||
upstream.as_str().unwrap().split('/').collect::<Vec<&str>>()[2],
|
.reduced
|
||||||
|
.permissions(gix::open::Permissions {
|
||||||
|
config,
|
||||||
|
..gix::open::Permissions::default_for_level(gix::sec::Trust::Reduced)
|
||||||
|
});
|
||||||
|
git_open_opts_map.full =
|
||||||
|
git_open_opts_map.full.permissions(gix::open::Permissions {
|
||||||
|
config,
|
||||||
|
..gix::open::Permissions::default_for_level(gix::sec::Trust::Full)
|
||||||
|
});
|
||||||
|
let shared_repo =
|
||||||
|
match ThreadSafeRepository::discover_with_environment_overrides_opts(
|
||||||
|
path,
|
||||||
|
Default::default(),
|
||||||
|
git_open_opts_map,
|
||||||
) {
|
) {
|
||||||
let path = entry
|
Ok(repo) => repo,
|
||||||
.path()
|
Err(e) => {
|
||||||
.strip_prefix(Path::new(dir))?
|
return Err(e.into());
|
||||||
.to_str()
|
}
|
||||||
.unwrap()
|
};
|
||||||
.to_string();
|
let repository = shared_repo.to_thread_local();
|
||||||
|
let branch = get_current_branch(&repository);
|
||||||
|
let remote = get_remote_for_branch(&repository, branch.as_deref());
|
||||||
|
if let Some(branch) = branch &&
|
||||||
|
let Some(remote) = remote &&
|
||||||
|
let Ok(remote_url) = get_url(&repository, &remote) {
|
||||||
|
let relative_path = entry.path().strip_prefix(Path::new(dir))?.to_str().unwrap().to_string();
|
||||||
repos.insert(
|
repos.insert(
|
||||||
path,
|
relative_path,
|
||||||
PersistableRepo {
|
PersistableRepo {
|
||||||
remote_url: remote.url().unwrap_or("None").to_owned(),
|
remote_url,
|
||||||
head: head.to_owned(),
|
head: branch,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
fs::write("gitice.lock", toml::to_string(&repos)?).expect("could not write to lockfile!");
|
fs::write("gitice.lock", toml::to_string(&repos)?).expect("could not write to lockfile!");
|
||||||
println!(
|
tracing::info!(
|
||||||
"Successfully generated lockfile with {} repos",
|
"Successfully generated lockfile with {} repos",
|
||||||
&repos.len()
|
&repos.len()
|
||||||
);
|
);
|
||||||
|
@ -84,3 +105,44 @@ pub(crate) fn thaw_repos(dir: &str, lockfile: &str) -> anyhow::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_current_branch(repository: &Repository) -> Option<String> {
|
||||||
|
let name = repository.head_name().ok()??;
|
||||||
|
let shorthand = name.shorten();
|
||||||
|
|
||||||
|
Some(shorthand.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_remote_for_branch(repository: &Repository, branch_name: Option<&str>) -> Option<String> {
|
||||||
|
let branch_name = branch_name?;
|
||||||
|
repository
|
||||||
|
.branch_remote_name(branch_name)
|
||||||
|
.map(|n| n.as_bstr().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_url(repo: &Repository, remote_name: &str) -> anyhow::Result<String> {
|
||||||
|
let config = repo.config_snapshot();
|
||||||
|
let remotes = match config.plumbing().sections_by_name("remote") {
|
||||||
|
Some(sections) => sections,
|
||||||
|
None => return Ok(Default::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut remote_url: Option<String> = None;
|
||||||
|
for (name, url) in remotes.filter_map(|section| {
|
||||||
|
let remote_name = section.header().subsection_name()?;
|
||||||
|
let url = section.value("url")?;
|
||||||
|
(remote_name, url).into()
|
||||||
|
}) {
|
||||||
|
remote_url = url.to_string().into();
|
||||||
|
if name == remote_name {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let remote_url = match remote_url {
|
||||||
|
Some(url) => url,
|
||||||
|
None => return Ok(Default::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(remote_url)
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(let_chains)]
|
||||||
pub(crate) mod cli;
|
pub(crate) mod cli;
|
||||||
pub(crate) mod git;
|
pub(crate) mod git;
|
||||||
pub(crate) mod logging;
|
pub(crate) mod logging;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue