mirror of
https://github.com/msfjarvis/gitice
synced 2025-08-14 20:57:01 +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]
|
||||
anyhow = "1.0.71"
|
||||
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_derive = "1.0.162"
|
||||
toml = "0.7.3"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[toolchain]
|
||||
channel = "stable"
|
||||
channel = "nightly-2023-02-22"
|
||||
components = [ "clippy", "rustfmt", "rust-src" ]
|
||||
targets = [ "x86_64-unknown-linux-gnu" ]
|
||||
profile = "minimal"
|
||||
|
|
126
src/git.rs
126
src/git.rs
|
@ -1,5 +1,5 @@
|
|||
use crate::model::PersistableRepo;
|
||||
use git2::Repository;
|
||||
use gix::{sec::trust::DefaultForLevel, Repository, ThreadSafeRepository};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
|
@ -17,42 +17,63 @@ pub(crate) fn freeze_repos(dir: &str) -> anyhow::Result<()> {
|
|||
if entry.file_type().is_dir() {
|
||||
let path = format!("{}/.git", entry.path().display());
|
||||
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() {
|
||||
let repo = Repository::open(git_dir)?;
|
||||
if repo.is_empty()? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let head = repo.head()?;
|
||||
if let Some(head) = head.name() {
|
||||
if let Ok(upstream) = repo.branch_upstream_name(head) {
|
||||
if let Ok(remote) = repo.find_remote(
|
||||
// This is a rather ugly hack, but not sure how else to get the required name
|
||||
// doesn't seem to work with the full name such as `refs/remotes/origin/master`
|
||||
upstream.as_str().unwrap().split('/').collect::<Vec<&str>>()[2],
|
||||
) {
|
||||
let path = entry
|
||||
.path()
|
||||
.strip_prefix(Path::new(dir))?
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
repos.insert(
|
||||
path,
|
||||
PersistableRepo {
|
||||
remote_url: remote.url().unwrap_or("None").to_owned(),
|
||||
head: head.to_owned(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// don't use the global git configs
|
||||
let config = gix::open::permissions::Config {
|
||||
git_binary: false,
|
||||
system: false,
|
||||
git: false,
|
||||
user: false,
|
||||
env: true,
|
||||
includes: true,
|
||||
};
|
||||
// change options for config permissions without touching anything else
|
||||
git_open_opts_map.reduced =
|
||||
git_open_opts_map
|
||||
.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,
|
||||
) {
|
||||
Ok(repo) => repo,
|
||||
Err(e) => {
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
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(
|
||||
relative_path,
|
||||
PersistableRepo {
|
||||
remote_url,
|
||||
head: branch,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
fs::write("gitice.lock", toml::to_string(&repos)?).expect("could not write to lockfile!");
|
||||
println!(
|
||||
tracing::info!(
|
||||
"Successfully generated lockfile with {} repos",
|
||||
&repos.len()
|
||||
);
|
||||
|
@ -84,3 +105,44 @@ pub(crate) fn thaw_repos(dir: &str, lockfile: &str) -> anyhow::Result<()> {
|
|||
|
||||
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 git;
|
||||
pub(crate) mod logging;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue