Skip to content

Commit cd6dc20

Browse files
Refactor: drop gitoxide from josh-core (#1337)
While gitoxide provides a well designed set of APIs, it's more oriented towards implementing a git client than a server, and it lacks some high-level APIs like treebuilder etc. Having it alongside the regular git2 implementation works but creates additional I/O pressure which has performance implications in scenarios when a lot of transactions are opened (graphql). It would still make sense to integrate gitoxide in the future as APIs improve, but only as a complete replacement of git2 and not side by side * Remove gix from josh-core * I kept gix in proxy since it still provides nice Rust APIs for repo init and config manipulation, however... * ...I updated the version of gix to latest and disabled all extra features, which reduced dependencies a lot
1 parent 3768e10 commit cd6dc20

File tree

10 files changed

+121
-591
lines changed

10 files changed

+121
-591
lines changed

Cargo.lock

Lines changed: 88 additions & 525 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ codegen-units = 1
1919
defer = "0.1.0"
2020
env_logger = "0.10.0"
2121
futures = "0.3.28"
22-
gix = "0.54.1"
22+
gix = { version = "0.63.0", default-features = false }
2323
hyper-reverse-proxy = "0.5.1"
2424
lazy_static = "1.4.0"
2525
libc = "0.2.148"

josh-core/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ sled = "0.34.7"
3434
strfmt = "0.2.4"
3535
toml = { workspace = true }
3636
tracing = { workspace = true }
37-
gix = { workspace = true }
3837
juniper = { workspace = true }
3938
form_urlencoded = "1.2.1"
4039

josh-core/src/cache.rs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ struct Transaction2 {
6868
pub struct Transaction {
6969
t2: std::cell::RefCell<Transaction2>,
7070
repo: git2::Repository,
71-
oxide_repo: gix::Repository,
7271
ref_prefix: String,
7372
}
7473

@@ -83,7 +82,6 @@ impl Transaction {
8382
git2::RepositoryOpenFlags::NO_SEARCH,
8483
&[] as &[&std::ffi::OsStr],
8584
)?,
86-
gix::ThreadSafeRepository::open(path)?.to_thread_local(),
8785
ref_prefix,
8886
))
8987
}
@@ -95,11 +93,7 @@ impl Transaction {
9593
load(&path)?
9694
};
9795

98-
Ok(Transaction::new(
99-
repo,
100-
gix::ThreadSafeRepository::open(path)?.to_thread_local(),
101-
None,
102-
))
96+
Ok(Transaction::new(repo, None))
10397
}
10498

10599
pub fn status(&self, _msg: &str) {
@@ -108,11 +102,7 @@ impl Transaction {
108102
/* t2.out.flush().ok(); */
109103
}
110104

111-
fn new(
112-
repo: git2::Repository,
113-
oxide_repo: gix::Repository,
114-
ref_prefix: Option<&str>,
115-
) -> Transaction {
105+
fn new(repo: git2::Repository, ref_prefix: Option<&str>) -> Transaction {
116106
log::debug!("new transaction");
117107
let path_tree = DB
118108
.lock()
@@ -151,7 +141,6 @@ impl Transaction {
151141
walks: 0,
152142
}),
153143
repo,
154-
oxide_repo,
155144
ref_prefix: ref_prefix.unwrap_or("").to_string(),
156145
}
157146
}
@@ -164,10 +153,6 @@ impl Transaction {
164153
&self.repo
165154
}
166155

167-
pub fn oxide_repo(&self) -> &gix::Repository {
168-
&self.oxide_repo
169-
}
170-
171156
pub fn refname(&self, r: &str) -> String {
172157
format!("{}{}", self.ref_prefix, r)
173158
}

josh-core/src/compat.rs

Lines changed: 0 additions & 9 deletions
This file was deleted.

josh-core/src/history.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use std::collections::HashMap;
23

34
pub fn walk2(
45
filter: filter::Filter,

josh-core/src/housekeeping.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use git2;
2-
3-
use super::*;
1+
use crate::*;
2+
use itertools::Itertools;
43
use std::collections::{BTreeSet, HashMap};
5-
use std::path::{Path, PathBuf};
4+
use std::path::Path;
65
use tracing::{info, span, Level};
76

87
pub type KnownViews = HashMap<String, (git2::Oid, BTreeSet<String>)>;
@@ -13,28 +12,33 @@ lazy_static! {
1312
}
1413

1514
pub fn list_refs(
16-
repo: &gix::Repository,
15+
repo: &git2::Repository,
1716
upstream_repo: &str,
18-
) -> JoshResult<Vec<(PathBuf, gix::ObjectId)>> {
17+
) -> JoshResult<Vec<(String, git2::Oid)>> {
1918
let mut refs = vec![];
2019

2120
let prefix = ["refs", "josh", "upstream", &to_ns(upstream_repo)]
2221
.iter()
23-
.collect::<PathBuf>();
22+
.join("/");
2423

25-
for group in [
26-
prefix.join("refs").join("heads"),
27-
prefix.join("refs").join("tags"),
24+
for glob in [
25+
format!("{}/refs/heads/*", &prefix),
26+
format!("{}/refs/tags/*", &prefix),
2827
]
2928
.iter()
3029
{
31-
for reference in repo.references()?.prefixed(group)? {
30+
for reference in repo.references_glob(&glob)? {
3231
let reference =
3332
reference.map_err(|e| josh_error(&format!("unable to obtain reference: {}", e)))?;
3433

35-
let name = reference.name().to_path().strip_prefix(&prefix)?;
36-
let oid = gix::ObjectId::from(reference.target().id());
37-
refs.push((name.to_owned(), oid))
34+
if let (Some(name), Some(target)) = (reference.name(), reference.target()) {
35+
let name = name
36+
.strip_prefix(&prefix)
37+
.and_then(|name| name.strip_prefix('/'))
38+
.ok_or_else(|| josh_error("bug: unexpected result of a glob"))?;
39+
40+
refs.push((name.to_owned(), target))
41+
}
3842
}
3943
}
4044

josh-core/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ extern crate pest_derive;
3434
#[macro_use]
3535
extern crate serde_json;
3636

37-
use std::collections::HashMap;
38-
3937
pub mod cache;
40-
pub mod compat;
4138
pub mod filter;
4239
pub mod graphql;
4340
pub mod history;
@@ -367,14 +364,14 @@ pub fn normalize_path(path: &std::path::Path) -> std::path::PathBuf {
367364
ret
368365
}
369366

370-
type Users = HashMap<String, User>;
367+
type Users = std::collections::HashMap<String, User>;
371368

372369
#[derive(Debug, serde::Deserialize)]
373370
struct User {
374371
pub groups: toml::value::Array,
375372
}
376373

377-
type Groups = HashMap<String, HashMap<String, Group>>;
374+
type Groups = std::collections::HashMap<String, std::collections::HashMap<String, Group>>;
378375
#[derive(Debug, serde::Deserialize)]
379376
struct Group {
380377
pub whitelist: String,

josh-filter/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ serde = { workspace = true }
1616
serde_json = { workspace = true }
1717
serde_yaml = { workspace = true }
1818
defer = { workspace = true }
19-
gix = { workspace = true }
2019
clap = { workspace = true }
2120
rs_tracing = { workspace = true }
2221
juniper = { workspace = true }

josh-proxy/src/bin/josh-proxy.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use hyper::service::{make_service_fn, service_fn};
1717
use hyper::{Request, Response, Server, StatusCode};
1818

1919
use indoc::formatdoc;
20-
use josh::compat::GitOxideCompatExt;
2120
use josh::{josh_error, JoshError, JoshResult};
2221
use josh_rpc::calls::RequestedCommand;
2322
use serde::Serialize;
@@ -433,7 +432,7 @@ async fn do_filter(
433432
)),
434433
)?;
435434

436-
let resolve_ref = |ref_value: &str| -> JoshResult<gix::ObjectId> {
435+
let resolve_ref = |ref_value: &str| -> JoshResult<git2::Oid> {
437436
let josh_name = [
438437
"refs",
439438
"josh",
@@ -445,42 +444,39 @@ async fn do_filter(
445444
.collect::<PathBuf>();
446445

447446
Ok(transaction
448-
.oxide_repo()
447+
.repo()
449448
.find_reference(josh_name.to_str().unwrap())
450449
.map_err(|e| josh_error(&format!("Could not find ref: {}", e)))?
451-
.id()
452-
.into())
450+
.target()
451+
.ok_or(josh_error("Could not resolve ref"))?)
453452
};
454453

455454
let (refs_list, head_ref) = match &head_ref {
456455
HeadRef::Explicit(ref_value)
457456
if ref_value.starts_with("refs/") || ref_value == "HEAD" =>
458457
{
459458
let object = resolve_ref(&ref_value)?;
460-
let list = vec![(PathBuf::from(ref_value), object)];
459+
let list = vec![(ref_value.clone(), object)];
461460

462461
(list, ref_value.clone())
463462
}
464463
HeadRef::Explicit(ref_value) => {
465464
// When it's not something starting with refs/ or HEAD, it's
466465
// probably sha1
467-
let list = vec![(
468-
PathBuf::from(ref_value),
469-
gix::ObjectId::from_str(&ref_value)?,
470-
)];
471-
let synthetic_ref = format!("refs/heads/_{}", ref_value);
466+
let list = vec![(ref_value.to_string(), git2::Oid::from_str(&ref_value)?)];
472467

468+
let synthetic_ref = format!("refs/heads/_{}", ref_value);
473469
(list, synthetic_ref)
474470
}
475471
HeadRef::Implicit => {
476472
// When user did not explicitly request a ref to filter,
477473
// start with a list of all existing refs
478474
let mut list =
479-
josh::housekeeping::list_refs(transaction.oxide_repo(), &meta.config.repo)?;
475+
josh::housekeeping::list_refs(transaction.repo(), &meta.config.repo)?;
480476

481477
let head_ref = head_ref.get().to_string();
482478
if let Ok(object) = resolve_ref(&head_ref) {
483-
list.push((PathBuf::from(&head_ref), object));
479+
list.push((head_ref.clone(), object));
484480
}
485481

486482
(list, head_ref)
@@ -497,11 +493,6 @@ async fn do_filter(
497493
head_ref
498494
};
499495

500-
let refs_list = refs_list
501-
.iter()
502-
.map(|(reference, oid)| (reference.to_str().unwrap().to_string(), oid.to_git2()))
503-
.collect::<Vec<_>>();
504-
505496
let t2 = josh::cache::Transaction::open(&repo_path.join("overlay"), None)?;
506497
t2.repo()
507498
.odb()?

0 commit comments

Comments
 (0)