diff --git a/Cargo.lock b/Cargo.lock index 97cd296..d0c07cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,15 +88,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "arc-swap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" -dependencies = [ - "rustversion", -] - [[package]] name = "async-trait" version = "0.1.89" @@ -655,29 +646,12 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.11.1" @@ -772,15 +746,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "clru" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" -dependencies = [ - "hashbrown 0.16.1", -] - [[package]] name = "cmake" version = "0.1.58" @@ -960,15 +925,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -985,32 +941,12 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "faster-hex" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" -dependencies = [ - "heapless", - "serde", -] - [[package]] name = "fastrand" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -[[package]] -name = "filetime" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" -dependencies = [ - "cfg-if", - "libc", -] - [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1308,10 +1244,8 @@ dependencies = [ name = "git-cache-git" version = "0.1.0" dependencies = [ - "async-trait", "bytes", "git-cache-core", - "gix", "tokio", "tracing", ] @@ -1348,638 +1282,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "gix" -version = "0.84.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae54ae0ebd1a5a3c3f8d95dd3b5ca6e63f4fed9bfd585e13801a97d7bde8f9ce" -dependencies = [ - "gix-actor", - "gix-commitgraph", - "gix-config", - "gix-date", - "gix-diff", - "gix-discover", - "gix-error", - "gix-features", - "gix-fs", - "gix-glob", - "gix-hash", - "gix-hashtable", - "gix-index", - "gix-lock", - "gix-object", - "gix-odb", - "gix-pack", - "gix-path", - "gix-protocol", - "gix-ref", - "gix-refspec", - "gix-revision", - "gix-revwalk", - "gix-sec", - "gix-shallow", - "gix-tempfile", - "gix-trace", - "gix-traverse", - "gix-url", - "gix-utils", - "gix-validate", - "gix-worktree-stream", - "nonempty", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-actor" -version = "0.41.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc998b8f746dda8565450d08a63b792ced9165d8c27a1ed3f02799ec6a7820f" -dependencies = [ - "bstr", - "gix-date", - "gix-error", -] - -[[package]] -name = "gix-attributes" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d43f12e246d3bf7ec624c8fc15ac4a4b62b7c4c6f586cb82be6c90bf84c9d02" -dependencies = [ - "bstr", - "gix-glob", - "gix-path", - "gix-quote", - "gix-trace", - "kstring", - "smallvec", - "thiserror", - "unicode-bom", -] - -[[package]] -name = "gix-bitmap" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ebef0c26ad305747649e727bbcd56a7b7910754eb7cea88f6dff6f93c51283" -dependencies = [ - "gix-error", -] - -[[package]] -name = "gix-chunk" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9faee47943b638e58ddd5e275a4906ad3e4b6c8584f1d41bd18ab9032ec52afb" -dependencies = [ - "gix-error", -] - -[[package]] -name = "gix-command" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00706d4fef135ef4b01680d5218c6ee40cda8baf697b864296cbc887d19118f6" -dependencies = [ - "bstr", - "gix-path", - "gix-quote", - "gix-trace", - "shell-words", -] - -[[package]] -name = "gix-commitgraph" -version = "0.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f675d0df484a7f6a47e64bd6f311af489d947c0323b0564f36d14f3d7762abb" -dependencies = [ - "bstr", - "gix-chunk", - "gix-error", - "gix-hash", - "memmap2", - "nonempty", -] - -[[package]] -name = "gix-config" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2372d4b49ca28431e7d150cab9d25edc1890f0184bd57eb0e917c7799e63de" -dependencies = [ - "bstr", - "gix-config-value", - "gix-features", - "gix-glob", - "gix-path", - "gix-ref", - "gix-sec", - "smallvec", - "thiserror", - "unicode-bom", -] - -[[package]] -name = "gix-config-value" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed42168329552f6c2e5df09665c104199d45d84bedb53683738a49b57fe1baab" -dependencies = [ - "bitflags", - "bstr", - "gix-path", - "libc", - "thiserror", -] - -[[package]] -name = "gix-date" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ecab64a98bbac9f8e02990a9ea5e3c974a7d49b95f2bd70ad94ad22fa6b48c" -dependencies = [ - "bstr", - "gix-error", - "itoa", - "jiff", -] - -[[package]] -name = "gix-diff" -version = "0.64.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6d9528f32d94cef2edf39a1ac01fe5a0fc44ddbb18d9e44099936047c3302b" -dependencies = [ - "bstr", - "gix-hash", - "gix-object", - "thiserror", -] - -[[package]] -name = "gix-discover" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77bacdd12b7879d2178a80c58c2f319995e4654e1a7a23e3181e5c8a12b824f7" -dependencies = [ - "bstr", - "dunce", - "gix-fs", - "gix-path", - "gix-ref", - "gix-sec", - "thiserror", -] - -[[package]] -name = "gix-error" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57831e199be480af90dcd7e459abed8a174c09ec9a6e2cc8f7ca6c54598b06b" -dependencies = [ - "bstr", -] - -[[package]] -name = "gix-features" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1849ae154d38bc403185be14fa871e38e3c93ee606875d94e207fdb9fba52dbc" -dependencies = [ - "bytes", - "crc32fast", - "gix-path", - "gix-trace", - "gix-utils", - "libc", - "once_cell", - "prodash", - "thiserror", - "walkdir", - "zlib-rs", -] - -[[package]] -name = "gix-filter" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecf74b7d16f6694ce4a3049074c41be0c7987105743674f1671807bd6dce09fa" -dependencies = [ - "bstr", - "encoding_rs", - "gix-attributes", - "gix-command", - "gix-hash", - "gix-object", - "gix-packetline", - "gix-path", - "gix-quote", - "gix-trace", - "gix-utils", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-fs" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdff46db8798e47e2f727d84b9379aac5add3dd3d9d0b07bb4d7d5d640771fe" -dependencies = [ - "bstr", - "fastrand", - "gix-features", - "gix-path", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-glob" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1fcb8ef5b16bcf874abe9b68d8abb3c0493c876d367ab824151f30a0f3f3756" -dependencies = [ - "bitflags", - "bstr", - "gix-features", - "gix-path", -] - -[[package]] -name = "gix-hash" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0926d3819c837750b4e03c7754901e73f68b8c9b690753a6372a1bed4eedce" -dependencies = [ - "faster-hex", - "gix-features", - "sha1-checked", - "thiserror", -] - -[[package]] -name = "gix-hashtable" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0e30b93eea8718baf7d8153fcb938e2926175bbf18097c09f1c01b6f0be0563" -dependencies = [ - "gix-hash", - "hashbrown 0.17.1", - "parking_lot", -] - -[[package]] -name = "gix-index" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6b28cc592dc753adb58302bb14a64e412ee591a3bec77aa4df87bff74fa80d" -dependencies = [ - "bitflags", - "bstr", - "filetime", - "fnv", - "gix-bitmap", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-traverse", - "gix-utils", - "gix-validate", - "hashbrown 0.17.1", - "itoa", - "libc", - "memmap2", - "rustix", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-lock" -version = "23.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c9dedd9e90b0d47624d2ed241d394e09294118364e87b9b7e5f1fe755f3c2c" -dependencies = [ - "gix-tempfile", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-object" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5cd857e29429c7213bdef3f5aef83f8cc124774fe8ae0d27b1607d218d6d525" -dependencies = [ - "bstr", - "gix-actor", - "gix-date", - "gix-features", - "gix-hash", - "gix-hashtable", - "gix-utils", - "gix-validate", - "itoa", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-odb" -version = "0.81.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d004c32858b1556f2d7874405edb3c97dc78fc09beaa87d57bb077ee2858a7d" -dependencies = [ - "arc-swap", - "gix-features", - "gix-fs", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-pack", - "gix-path", - "gix-quote", - "memmap2", - "parking_lot", - "tempfile", - "thiserror", -] - -[[package]] -name = "gix-pack" -version = "0.71.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43626f2a27d1033674ec1a196b845614231e6bbd949d5e21c133045ff56b174" -dependencies = [ - "clru", - "gix-chunk", - "gix-error", - "gix-features", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-path", - "memmap2", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-packetline" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18337ba2830bb43367d1af43819c8c78f31337f079fc76d0f1f1750a173126" -dependencies = [ - "bstr", - "faster-hex", - "gix-trace", - "thiserror", -] - -[[package]] -name = "gix-path" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa6ac14cd14939ea94a496ce7460daa6511c09f5b84757e9cfc6f9c8d0f93a6" -dependencies = [ - "bstr", - "gix-trace", - "gix-validate", - "thiserror", -] - -[[package]] -name = "gix-protocol" -version = "0.62.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51dea3acb390707ab868f1f9584f18449eb95d869deffae96768e47d303595ee" -dependencies = [ - "bstr", - "gix-date", - "gix-features", - "gix-hash", - "gix-ref", - "gix-shallow", - "gix-transport", - "gix-utils", - "maybe-async", - "nonempty", - "thiserror", -] - -[[package]] -name = "gix-quote" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e541fc33cc2b783b7979040d445a0c86a2eca747c8faea4ca84230d06ae6ef" -dependencies = [ - "bstr", - "gix-error", - "gix-utils", -] - -[[package]] -name = "gix-ref" -version = "0.64.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c04f64c37eb7e6feb73c7060f8dc6f381cc5de5d53249bfd450bc48a86b2e8b" -dependencies = [ - "gix-actor", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-path", - "gix-tempfile", - "gix-utils", - "gix-validate", - "memmap2", - "thiserror", -] - -[[package]] -name = "gix-refspec" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b216ae06ec74b5f24ad0142026a997fb0a935b7410eaf9c1616fc3f0e6c5a6d3" -dependencies = [ - "bstr", - "gix-error", - "gix-glob", - "gix-hash", - "gix-revision", - "gix-validate", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-revision" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c88884dd3c1a19a39da19d10211fcdea2809aadc86869b6e824a1774340f" -dependencies = [ - "bitflags", - "bstr", - "gix-commitgraph", - "gix-date", - "gix-error", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-revwalk", - "gix-trace", - "nonempty", -] - -[[package]] -name = "gix-revwalk" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f5756abffe0917827aac683b13684ed99875bc398fa1f9b8f479b0681ef9e6" -dependencies = [ - "gix-commitgraph", - "gix-date", - "gix-error", - "gix-hash", - "gix-hashtable", - "gix-object", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-sec" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8519976e4c7e486270740a5400369f37940779b80bd1377d94cfa1125d01b3" -dependencies = [ - "bitflags", - "gix-path", - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "gix-shallow" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a292fc2fe548c5dfa575479d16b445b0ddf1dd2f56f1fec6aed386f82553cd97" -dependencies = [ - "bstr", - "gix-hash", - "gix-lock", - "nonempty", - "thiserror", -] - -[[package]] -name = "gix-tempfile" -version = "23.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27850097e1ff9515f46a0dad0f5f9c9d020e972727772dabab9450690c4adb22" -dependencies = [ - "gix-fs", - "libc", - "parking_lot", - "tempfile", -] - -[[package]] -name = "gix-trace" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dc45eae785c0eb14173e0f152e6e224dcf4d45b6a6999a3aed22af541ad678" - -[[package]] -name = "gix-transport" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0e34995b1aab0fa8dff2af8db726a0bfad3e119c89302604463264046e7ff" -dependencies = [ - "bstr", - "gix-command", - "gix-features", - "gix-packetline", - "gix-quote", - "gix-sec", - "gix-url", - "thiserror", -] - -[[package]] -name = "gix-traverse" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de590ecc86a3b2870665f2288324fa9f7f8672c7fc2d4e020fdd81cd1f7aed" -dependencies = [ - "bitflags", - "gix-commitgraph", - "gix-date", - "gix-hash", - "gix-hashtable", - "gix-object", - "gix-revwalk", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-url" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bb01ec69d55e82ccb7a19e264501ead4e6aac38463a8cebfdd81e22bb67ab2" -dependencies = [ - "bstr", - "gix-path", - "percent-encoding", - "thiserror", -] - -[[package]] -name = "gix-utils" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c50966184123caf580ffa64e28031a878597f1c7fceb8fe19566c38eb1b771" -dependencies = [ - "fastrand", - "unicode-normalization", -] - -[[package]] -name = "gix-validate" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc6fc771c4063ba7cd2f47b91fb6076251c6a823b64b7fe7b8874b0fe4afae3" -dependencies = [ - "bstr", -] - -[[package]] -name = "gix-worktree-stream" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25e9ed30100c63f7590bc581c225e53f731a53e06aa79a245739c07f7dcc557" -dependencies = [ - "gix-attributes", - "gix-error", - "gix-features", - "gix-filter", - "gix-fs", - "gix-hash", - "gix-object", - "gix-path", - "gix-traverse", - "parking_lot", -] - [[package]] name = "h2" version = "0.4.14" @@ -1999,15 +1301,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.15.5" @@ -2033,21 +1326,6 @@ name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] [[package]] name = "heck" @@ -2371,47 +1649,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" -[[package]] -name = "jiff" -version = "0.2.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" -dependencies = [ - "jiff-static", - "jiff-tzdb-platform", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", - "windows-link", -] - -[[package]] -name = "jiff-static" -version = "0.2.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jiff-tzdb" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" - -[[package]] -name = "jiff-tzdb-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" -dependencies = [ - "jiff-tzdb", -] - [[package]] name = "jobserver" version = "0.1.34" @@ -2434,15 +1671,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kstring" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" -dependencies = [ - "static_assertions", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -2473,15 +1701,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -2518,17 +1737,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" -[[package]] -name = "maybe-async" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "md-5" version = "0.11.0" @@ -2545,15 +1753,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "memmap2" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" -dependencies = [ - "libc", -] - [[package]] name = "mime" version = "0.3.17" @@ -2581,12 +1780,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "nonempty" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9737e026353e5cd0736f98eddae28665118eb6f6600902a7f50db585621fecb6" - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2644,29 +1837,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -2685,21 +1855,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "portable-atomic-util" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" -dependencies = [ - "portable-atomic", -] - [[package]] name = "potential_utf" version = "0.1.5" @@ -2743,15 +1898,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prodash" -version = "31.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c" -dependencies = [ - "parking_lot", -] - [[package]] name = "quinn" version = "0.11.9" @@ -2857,15 +2003,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - [[package]] name = "regex-automata" version = "0.4.14" @@ -3033,15 +2170,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "schannel" version = "0.1.29" @@ -3051,12 +2179,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "3.7.0" @@ -3183,16 +2305,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha1-checked" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" -dependencies = [ - "digest 0.10.7", - "sha1 0.10.6", -] - [[package]] name = "sha2" version = "0.10.9" @@ -3224,12 +2336,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-words" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" - [[package]] name = "shlex" version = "1.3.0" @@ -3286,12 +2392,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -3643,27 +2743,12 @@ version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" -[[package]] -name = "unicode-bom" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" - [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-normalization" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-xid" version = "0.2.6" @@ -3736,16 +2821,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -3910,15 +2985,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "windows-core" version = "0.62.2" @@ -4278,12 +3344,6 @@ dependencies = [ "syn", ] -[[package]] -name = "zlib-rs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" - [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index bcd8826..b6d7fa7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ chrono = { version = "0.4.41", features = ["serde"] } clap = { version = "4.5.38", features = ["derive", "env"] } flate2 = "1.1" futures = "0.3" -gix = { version = "0.84", default-features = false, features = ["revision", "sha1"] } http = "1.3.1" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } serde = { version = "1.0.219", features = ["derive"] } diff --git a/README.md b/README.md index 8986c07..b1b3894 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,6 @@ from the file. | `GIT_CACHE_MAX_GIT_OUTPUT_BYTES` | 16 MiB | Upper bound on captured Git subprocess output. | | `GIT_CACHE_MAX_CONCURRENT_GIT_PROCESSES` | `64` | Semaphore limiting concurrent Git subprocesses (the main CPU/memory knob). | | `GIT_CACHE_ASYNC_MATERIALIZE_CONCURRENCY` | `2` | Concurrency for background materialization work. | -| `GIT_CACHE_USE_GITOXIDE` | `true` | Use in-process gitoxide for local read-only Git operations; disable as a kill switch to fall back to the `git` binary. | | `GIT_CACHE_UPSTREAM_AUTH_TOKEN_ENV` | unset | Name of another env var holding a deployment-wide upstream token, injected via Git config env (never argv or manifests). | ### Disk diff --git a/crates/git-cache-api/src/tests.rs b/crates/git-cache-api/src/tests.rs index 5342b27..d80181b 100644 --- a/crates/git-cache-api/src/tests.rs +++ b/crates/git-cache-api/src/tests.rs @@ -263,7 +263,6 @@ async fn proxy_warm_task_queues_async_generation_materialize() { max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: 1, public_path_prefix: String::new(), - use_gitoxide: true, }; let state = Arc::new(ApiState::try_new(config).unwrap()); let materializer = Materializer::new(Arc::clone(&state.domain)); @@ -393,7 +392,6 @@ async fn proxy_warm_task_publishes_served_commit_when_branch_moves() { max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: 1, public_path_prefix: String::new(), - use_gitoxide: true, }; let state = Arc::new(ApiState::try_new(config).unwrap()); let materializer = Materializer::new(Arc::clone(&state.domain)); @@ -485,7 +483,6 @@ async fn authenticated_resolve_is_rate_limited_before_upstream_work() { max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: git_cache_core::default_async_materialize_concurrency(), public_path_prefix: String::new(), - use_gitoxide: true, }; let state = Arc::new(ApiState::try_new(config).unwrap()); assert!(state.rate_limiter.check(), "first request consumes quota"); @@ -535,7 +532,6 @@ async fn healthz_fails_after_shutdown_begins() { max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: git_cache_core::default_async_materialize_concurrency(), public_path_prefix: String::new(), - use_gitoxide: true, }; let state = Arc::new(ApiState::try_new(config).unwrap()); let gate = ReadinessGate(Arc::clone(&state.shutting_down)); diff --git a/crates/git-cache-api/tests/git_client_advanced.rs b/crates/git-cache-api/tests/git_client_advanced.rs index 5c9e9ff..da99b07 100644 --- a/crates/git-cache-api/tests/git_client_advanced.rs +++ b/crates/git-cache-api/tests/git_client_advanced.rs @@ -26,19 +26,18 @@ mod tests { impl TestServer { async fn start() -> Self { - Self::start_inner(false, true).await + Self::start_inner(false).await } /// Like `start`, but the server reaches the upstream via a `file://` /// URL instead of a bare path. Git only registers promisor/partial /// clone state for URL-shaped remotes ("promisor remote name cannot /// begin with '/'"), so filtered-fetch tests need this variant. - /// `use_gitoxide` selects the local backend (gix vs git subprocess). - async fn start_with_file_url_upstream(use_gitoxide: bool) -> Self { - Self::start_inner(true, use_gitoxide).await + async fn start_with_file_url_upstream() -> Self { + Self::start_inner(true).await } - async fn start_inner(file_url_upstream: bool, use_gitoxide: bool) -> Self { + async fn start_inner(file_url_upstream: bool) -> Self { let tmp = TempDir::new().unwrap(); let upstream_bare = tmp.path().join("upstreams/github.com/org/repo.git"); let upstream_work = tmp.path().join("work"); @@ -70,7 +69,7 @@ mod tests { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); - let mut config = if file_url_upstream { + let config = if file_url_upstream { support::test_config_with_upstream( addr, tmp.path(), @@ -79,7 +78,6 @@ mod tests { } else { support::test_config(addr, tmp.path()) }; - config.use_gitoxide = use_gitoxide; let router = app(config); @@ -419,17 +417,8 @@ mod tests { /// to support filters (`uploadpack.allowFilter`), like real upstreams do; /// without it the filter is silently ignored and the bug cannot trigger. #[tokio::test(flavor = "multi_thread")] - async fn full_clone_succeeds_after_blobless_shallow_hydration_gix_backend() { - full_clone_after_blobless_shallow_hydration(true).await; - } - - #[tokio::test(flavor = "multi_thread")] - async fn full_clone_succeeds_after_blobless_shallow_hydration_git_backend() { - full_clone_after_blobless_shallow_hydration(false).await; - } - - async fn full_clone_after_blobless_shallow_hydration(use_gitoxide: bool) { - let server = TestServer::start_with_file_url_upstream(use_gitoxide).await; + async fn full_clone_succeeds_after_blobless_shallow_hydration() { + let server = TestServer::start_with_file_url_upstream().await; run_git( &server.upstream_bare, &["config", "uploadpack.allowFilter", "true"], @@ -497,7 +486,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn materialize_branch_succeeds_after_blobless_shallow_hydration() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; run_git( &server.upstream_bare, &["config", "uploadpack.allowFilter", "true"], @@ -619,7 +608,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn deepen_after_cold_blobless_shallow_hydration_extends_history() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; run_git( &server.upstream_bare, &["config", "uploadpack.allowFilter", "true"], @@ -670,7 +659,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn fresh_blobless_depth_clone_expands_after_depth1_cache_warm() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; run_git( &server.upstream_bare, &["config", "uploadpack.allowFilter", "true"], @@ -744,7 +733,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn blobless_depth_clone_succeeds_after_partial_non_shallow_hot_cache() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; run_git( &server.upstream_bare, &["config", "uploadpack.allowFilter", "true"], @@ -835,7 +824,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn deepen_after_shallow_clone_does_not_unshallow_cache() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; // Six commits upstream (initial + five). A depth-1 seed then a // client --deepen=2 must extend the cache by exactly two commits and @@ -917,7 +906,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn full_clone_succeeds_after_shallow_generation_hydrates_cold_cache() { - let server = TestServer::start_with_file_url_upstream(true).await; + let server = TestServer::start_with_file_url_upstream().await; for message in [ "second shallow generation", diff --git a/crates/git-cache-api/tests/support/mod.rs b/crates/git-cache-api/tests/support/mod.rs index 0eab757..8056361 100644 --- a/crates/git-cache-api/tests/support/mod.rs +++ b/crates/git-cache-api/tests/support/mod.rs @@ -41,6 +41,5 @@ pub fn test_config_with_upstream( max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: git_cache_core::default_async_materialize_concurrency(), public_path_prefix: String::new(), - use_gitoxide: true, } } diff --git a/crates/git-cache-core/src/config.rs b/crates/git-cache-core/src/config.rs index f7b7e0a..d9a683c 100644 --- a/crates/git-cache-core/src/config.rs +++ b/crates/git-cache-core/src/config.rs @@ -38,10 +38,6 @@ pub struct AppConfig { pub async_materialize_concurrency: usize, #[serde(default)] pub public_path_prefix: String, - /// Use in-process gitoxide for local read-only Git operations instead of - /// spawning the `git` binary. Acts as a kill switch when disabled. - #[serde(default = "default_use_gitoxide")] - pub use_gitoxide: bool, } impl AppConfig { @@ -151,7 +147,6 @@ impl AppConfig { "GIT_CACHE_ASYNC_MATERIALIZE_CONCURRENCY", default_async_materialize_concurrency(), )?, - use_gitoxide: parse_bool_env("GIT_CACHE_USE_GITOXIDE", default_use_gitoxide())?, }) } } @@ -354,10 +349,6 @@ pub fn default_async_materialize_concurrency() -> usize { 8 } -pub fn default_use_gitoxide() -> bool { - true -} - fn default_shutdown_readiness_delay_seconds() -> u64 { 5 } diff --git a/crates/git-cache-core/src/config/tests.rs b/crates/git-cache-core/src/config/tests.rs index 6657f6b..8244f37 100644 --- a/crates/git-cache-core/src/config/tests.rs +++ b/crates/git-cache-core/src/config/tests.rs @@ -33,7 +33,6 @@ const ENV_KEYS: &[&str] = &[ "GIT_CACHE_SHUTDOWN_DRAIN_TIMEOUT_SECONDS", "GIT_CACHE_MAX_CONCURRENT_GIT_PROCESSES", "GIT_CACHE_ASYNC_MATERIALIZE_CONCURRENCY", - "GIT_CACHE_USE_GITOXIDE", "GIT_CACHE_LFS_MAX_OBJECT_BYTES", "GIT_CACHE_PUBLIC_PATH_PREFIX", ]; diff --git a/crates/git-cache-domain/src/materializer/tests/mod.rs b/crates/git-cache-domain/src/materializer/tests/mod.rs index 28c4ed2..2f297d9 100644 --- a/crates/git-cache-domain/src/materializer/tests/mod.rs +++ b/crates/git-cache-domain/src/materializer/tests/mod.rs @@ -143,7 +143,6 @@ impl GitFixture { max_concurrent_git_processes: git_cache_core::default_max_concurrent_git_processes(), async_materialize_concurrency: 2, public_path_prefix: String::new(), - use_gitoxide: true, } } diff --git a/crates/git-cache-domain/src/state.rs b/crates/git-cache-domain/src/state.rs index b3d8d9a..35e9f79 100644 --- a/crates/git-cache-domain/src/state.rs +++ b/crates/git-cache-domain/src/state.rs @@ -118,8 +118,7 @@ impl AppState { Duration::from_secs(config.git_timeout_seconds), config.max_concurrent_git_processes, ) - .with_output_limit(config.max_git_output_bytes) - .with_gitoxide(config.use_gitoxide); + .with_output_limit(config.max_git_output_bytes); let git = with_optional_upstream_credentials(git, &config); let disk = DiskManager::new( &config.cache_root, diff --git a/crates/git-cache-domain/src/state/tests.rs b/crates/git-cache-domain/src/state/tests.rs index d4a5516..7cb1885 100644 --- a/crates/git-cache-domain/src/state/tests.rs +++ b/crates/git-cache-domain/src/state/tests.rs @@ -69,6 +69,5 @@ fn test_config(cache_root: PathBuf, object_root: PathBuf) -> AppConfig { max_concurrent_git_processes: 1, async_materialize_concurrency: 2, public_path_prefix: String::new(), - use_gitoxide: true, } } diff --git a/crates/git-cache-fuzz/tests/materializer_fuzz.rs b/crates/git-cache-fuzz/tests/materializer_fuzz.rs index b109711..338495a 100644 --- a/crates/git-cache-fuzz/tests/materializer_fuzz.rs +++ b/crates/git-cache-fuzz/tests/materializer_fuzz.rs @@ -59,7 +59,6 @@ impl Fixture { max_concurrent_git_processes: 4, async_materialize_concurrency: 2, public_path_prefix: String::new(), - use_gitoxide: true, } } diff --git a/crates/git-cache-git/Cargo.toml b/crates/git-cache-git/Cargo.toml index aac6bd7..3e9360b 100644 --- a/crates/git-cache-git/Cargo.toml +++ b/crates/git-cache-git/Cargo.toml @@ -7,9 +7,7 @@ repository.workspace = true rust-version.workspace = true [dependencies] -async-trait.workspace = true bytes.workspace = true git-cache-core = { path = "../git-cache-core" } -gix.workspace = true tokio = { workspace = true, features = ["rt", "sync"] } tracing.workspace = true diff --git a/crates/git-cache-git/src/backend.rs b/crates/git-cache-git/src/backend.rs deleted file mode 100644 index db27293..0000000 --- a/crates/git-cache-git/src/backend.rs +++ /dev/null @@ -1,247 +0,0 @@ -//! Local read-only operation backends. -//! -//! `Git` delegates local read-only operations (`rev_parse`, ref listing, -//! ancestry checks, object type lookups) to a [`LocalGitBackend`]. Two -//! implementations exist: [`GixBackend`] runs in-process via gitoxide, and -//! [`GitBackend`] shells out to the `git` binary. Input validation happens in -//! the `Git` wrapper before dispatch, so backends receive pre-validated -//! arguments. - -use async_trait::async_trait; -use git_cache_core::{CommitSha, GitCacheError, Result}; -use std::collections::HashMap; -use std::path::Path; - -use crate::{gix_backend, Git}; - -#[async_trait] -pub(crate) trait LocalGitBackend: Send + Sync + std::fmt::Debug { - async fn rev_parse(&self, git: &Git, repo_dir: &Path, rev: &str) -> Result; - - async fn is_ancestor( - &self, - git: &Git, - repo_dir: &Path, - ancestor: &CommitSha, - descendant: &CommitSha, - ) -> Result; - - async fn for_each_ref_commits( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result>; - - async fn for_each_ref( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result>; - - async fn cat_file_batch_types( - &self, - git: &Git, - repo_dir: &Path, - object_ids: &[CommitSha], - ) -> Result>; -} - -/// In-process gitoxide implementation. Operations run on the blocking thread -/// pool, bounded by the same semaphore as git subprocesses. -#[derive(Debug)] -pub(crate) struct GixBackend; - -#[async_trait] -impl LocalGitBackend for GixBackend { - async fn rev_parse(&self, git: &Git, repo_dir: &Path, rev: &str) -> Result { - let repo_dir = repo_dir.to_path_buf(); - let rev = rev.to_string(); - git.run_gix(move || gix_backend::rev_parse(&repo_dir, &rev)) - .await - } - - async fn is_ancestor( - &self, - git: &Git, - repo_dir: &Path, - ancestor: &CommitSha, - descendant: &CommitSha, - ) -> Result { - let repo_dir = repo_dir.to_path_buf(); - let ancestor = ancestor.clone(); - let descendant = descendant.clone(); - git.run_gix(move || gix_backend::is_ancestor(&repo_dir, &ancestor, &descendant)) - .await - } - - async fn for_each_ref_commits( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result> { - let repo_dir = repo_dir.to_path_buf(); - let ref_prefix = ref_prefix.to_string(); - git.run_gix(move || gix_backend::for_each_ref_commits(&repo_dir, &ref_prefix)) - .await - } - - async fn for_each_ref( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result> { - let repo_dir = repo_dir.to_path_buf(); - let ref_prefix = ref_prefix.to_string(); - git.run_gix(move || gix_backend::for_each_ref(&repo_dir, &ref_prefix)) - .await - } - - async fn cat_file_batch_types( - &self, - git: &Git, - repo_dir: &Path, - object_ids: &[CommitSha], - ) -> Result> { - let repo_dir = repo_dir.to_path_buf(); - let object_ids = object_ids.to_vec(); - git.run_gix(move || gix_backend::cat_file_batch_types(&repo_dir, &object_ids)) - .await - } -} - -/// Subprocess implementation backed by the `git` binary. -#[derive(Debug)] -pub(crate) struct GitBackend; - -#[async_trait] -impl LocalGitBackend for GitBackend { - async fn rev_parse(&self, git: &Git, repo_dir: &Path, rev: &str) -> Result { - let output = git - .run( - Some(repo_dir), - ["rev-parse", "--verify", "--end-of-options", rev], - ) - .await?; - output - .stdout_utf8("rev-parse") - .map(|value| value.trim().to_string()) - } - - async fn is_ancestor( - &self, - git: &Git, - repo_dir: &Path, - ancestor: &CommitSha, - descendant: &CommitSha, - ) -> Result { - let output = git - .run( - Some(repo_dir), - [ - "rev-list", - "--max-count=1", - ancestor.as_str(), - "--not", - descendant.as_str(), - "--", - ], - ) - .await?; - Ok(output.stdout.iter().all(|byte| byte.is_ascii_whitespace())) - } - - async fn for_each_ref_commits( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result> { - let output = git - .run( - Some(repo_dir), - ["for-each-ref", "--format=%(objectname)", "--", ref_prefix], - ) - .await?; - let text = output.stdout_utf8("for-each-ref")?; - text.lines() - .filter(|line| !line.trim().is_empty()) - .map(|line| CommitSha::parse(line.trim())) - .collect() - } - - async fn for_each_ref( - &self, - git: &Git, - repo_dir: &Path, - ref_prefix: &str, - ) -> Result> { - let output = git - .run( - Some(repo_dir), - [ - "for-each-ref", - "--format=%(refname) %(objectname)", - "--", - ref_prefix, - ], - ) - .await?; - let text = output.stdout_utf8("for-each-ref")?; - let mut refs = Vec::new(); - for line in text.lines() { - let line = line.trim(); - if line.is_empty() { - continue; - } - let Some((ref_name, commit)) = line.split_once(' ') else { - return Err(GitCacheError::Validation(format!( - "malformed git for-each-ref output line: {line:?}" - ))); - }; - refs.push((ref_name.to_string(), CommitSha::parse(commit)?)); - } - Ok(refs) - } - - async fn cat_file_batch_types( - &self, - git: &Git, - repo_dir: &Path, - object_ids: &[CommitSha], - ) -> Result> { - let mut stdin = Vec::with_capacity(object_ids.len() * 41); - for object_id in object_ids { - stdin.extend_from_slice(object_id.as_str().as_bytes()); - stdin.push(b'\n'); - } - - let output = git - .run_with_stdin_and_limits( - Some(repo_dir), - ["cat-file", "--batch-check=%(objectname) %(objecttype)"], - Some(&stdin), - git.output_limit, - git.output_limit, - ) - .await?; - let text = output.stdout_utf8("cat-file")?; - - let mut types = HashMap::new(); - for line in text.lines() { - let Some((object_id, object_type)) = line.split_once(' ') else { - return Err(GitCacheError::Validation(format!( - "malformed git cat-file output line: {line:?}" - ))); - }; - if object_type == "missing" { - continue; - } - types.insert(CommitSha::parse(object_id)?, object_type.to_string()); - } - Ok(types) - } -} diff --git a/crates/git-cache-git/src/gix_backend.rs b/crates/git-cache-git/src/gix_backend.rs deleted file mode 100644 index 6260ad0..0000000 --- a/crates/git-cache-git/src/gix_backend.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! In-process implementations of local, read-only Git operations using -//! gitoxide (`gix`). These run inside the cache's bare repositories and never -//! touch the network. All functions are synchronous and intended to be called -//! through `tokio::task::spawn_blocking`. -//! -//! Inputs are validated by the `Git` wrapper before reaching this module, and -//! no subprocess is spawned, so there is no argv injection surface here. - -use git_cache_core::{CommitSha, GitCacheError, Result}; -use std::collections::HashMap; -use std::path::Path; - -fn open(repo_dir: &Path) -> Result { - gix::open_opts(repo_dir, gix::open::Options::isolated()).map_err(|err| { - GitCacheError::Validation(format!( - "gitoxide failed to open repository {}: {err}", - repo_dir.display() - )) - }) -} - -fn parse_object_id(value: &str) -> Result { - gix::ObjectId::from_hex(value.as_bytes()) - .map_err(|err| GitCacheError::Validation(format!("invalid object id {value:?}: {err}"))) -} - -/// Equivalent of `git rev-parse --verify --end-of-options {rev}`. -pub(crate) fn rev_parse(repo_dir: &Path, rev: &str) -> Result { - let repo = open(repo_dir)?; - let id = repo.rev_parse_single(rev).map_err(|err| { - GitCacheError::Validation(format!("gitoxide rev-parse failed for {rev:?}: {err}")) - })?; - Ok(id.detach().to_string()) -} - -/// Equivalent of `git for-each-ref --format='%(refname) %(objectname)' -- {prefix}`. -pub(crate) fn for_each_ref(repo_dir: &Path, ref_prefix: &str) -> Result> { - let repo = open(repo_dir)?; - let references = repo - .references() - .map_err(|err| GitCacheError::Validation(format!("gitoxide failed to read refs: {err}")))?; - let iter = references.prefixed(ref_prefix).map_err(|err| { - GitCacheError::Validation(format!( - "gitoxide failed to iterate refs with prefix {ref_prefix:?}: {err}" - )) - })?; - - let mut refs = Vec::new(); - for reference in iter { - let reference = reference.map_err(|err| { - GitCacheError::Validation(format!("gitoxide failed to read ref entry: {err}")) - })?; - let name = reference.name().as_bstr().to_string(); - let id = resolve_ref_object_id(reference)?; - refs.push((name, CommitSha::parse(id.to_string().as_str())?)); - } - Ok(refs) -} - -/// Equivalent of `git for-each-ref --format='%(objectname)' -- {prefix}`. -pub(crate) fn for_each_ref_commits(repo_dir: &Path, ref_prefix: &str) -> Result> { - Ok(for_each_ref(repo_dir, ref_prefix)? - .into_iter() - .map(|(_, commit)| commit) - .collect()) -} - -fn resolve_ref_object_id(reference: gix::Reference<'_>) -> Result { - let mut current = reference; - // Symbolic refs are followed to their direct target without peeling - // annotated tags, matching `%(objectname)` semantics. - for _ in 0..16 { - if let Some(id) = current.try_id() { - return Ok(id.detach()); - } - match current.follow() { - Some(next) => { - current = next.map_err(|err| { - GitCacheError::Validation(format!( - "gitoxide failed to follow symbolic ref: {err}" - )) - })?; - } - None => break, - } - } - Err(GitCacheError::Validation( - "gitoxide could not resolve ref to an object id".into(), - )) -} - -/// Equivalent of `git rev-list --max-count=1 {ancestor} --not {descendant}`: -/// true when every commit reachable from `ancestor` is also reachable from -/// `descendant`. -pub(crate) fn is_ancestor( - repo_dir: &Path, - ancestor: &CommitSha, - descendant: &CommitSha, -) -> Result { - let repo = open(repo_dir)?; - let ancestor_id = parse_object_id(ancestor.as_str())?; - let descendant_id = parse_object_id(descendant.as_str())?; - - let mut walk = repo - .rev_walk([ancestor_id]) - .with_hidden([descendant_id]) - .all() - .map_err(|err| { - GitCacheError::Validation(format!("gitoxide rev walk failed to start: {err}")) - })?; - match walk.next() { - Some(Err(err)) => Err(GitCacheError::Validation(format!( - "gitoxide rev walk failed: {err}" - ))), - Some(Ok(_)) => Ok(false), - None => Ok(true), - } -} - -/// Equivalent of `git cat-file --batch-check='%(objectname) %(objecttype)'`. -/// Missing objects are skipped. Object lookup never lazy-fetches, so this also -/// covers the `GIT_NO_LAZY_FETCH=1` variant. -pub(crate) fn cat_file_batch_types( - repo_dir: &Path, - object_ids: &[CommitSha], -) -> Result> { - let repo = open(repo_dir)?; - let mut types = HashMap::new(); - for object_id in object_ids { - let oid = parse_object_id(object_id.as_str())?; - match repo.try_find_header(oid) { - Ok(Some(header)) => { - types.insert(object_id.clone(), header.kind().to_string()); - } - Ok(None) => continue, - Err(err) => { - return Err(GitCacheError::Validation(format!( - "gitoxide object header lookup failed for {}: {err}", - object_id.as_str() - ))); - } - } - } - Ok(types) -} diff --git a/crates/git-cache-git/src/lib.rs b/crates/git-cache-git/src/lib.rs index e344379..9541ba2 100644 --- a/crates/git-cache-git/src/lib.rs +++ b/crates/git-cache-git/src/lib.rs @@ -14,11 +14,6 @@ use tokio::sync::{OwnedSemaphorePermit, Semaphore}; use tokio::time::timeout; use tracing::{debug, info}; -mod backend; -mod gix_backend; - -use backend::{GitBackend, GixBackend, LocalGitBackend}; - pub const DEFAULT_OUTPUT_LIMIT: usize = 4 * 1024 * 1024; const COMMIT_PARENT_BATCH_CHUNK_SIZE: usize = 512; @@ -30,7 +25,6 @@ pub struct Git { extra_env: Vec<(OsString, OsString)>, upstream_auth_env: Option, process_semaphore: Arc, - local_backend: Arc, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -125,7 +119,6 @@ impl Git { extra_env: Vec::new(), upstream_auth_env: None, process_semaphore: Arc::new(Semaphore::new(effective)), - local_backend: Arc::new(GixBackend), } } @@ -138,36 +131,6 @@ impl Git { self } - /// Select the backend for local read-only operations. In-process - /// gitoxide is the default; disabling routes everything through the - /// `git` binary. - pub fn with_gitoxide(mut self, use_gitoxide: bool) -> Self { - self.local_backend = if use_gitoxide { - Arc::new(GixBackend) as Arc - } else { - Arc::new(GitBackend) - }; - self - } - - /// Run a synchronous gitoxide operation on the blocking thread pool, - /// bounded by the same semaphore as git subprocesses. - async fn run_gix(&self, func: F) -> Result - where - F: FnOnce() -> Result + Send + 'static, - T: Send + 'static, - { - let _permit = self - .process_semaphore - .clone() - .acquire_owned() - .await - .map_err(|_| GitCacheError::Internal("git process semaphore closed".into()))?; - tokio::task::spawn_blocking(func) - .await - .map_err(|err| GitCacheError::Internal(format!("gitoxide task failed: {err}")))? - } - pub fn with_env(mut self, key: impl Into, value: impl Into) -> Self { self.extra_env.push((key.into(), value.into())); self @@ -187,10 +150,15 @@ impl Git { pub async fn rev_parse(&self, repo_dir: &Path, rev: &str) -> Result { reject_revision_arg(rev)?; - self.local_backend - .clone() - .rev_parse(self, repo_dir, rev) - .await + let output = self + .run( + Some(repo_dir), + ["rev-parse", "--verify", "--end-of-options", rev], + ) + .await?; + output + .stdout_utf8("rev-parse") + .map(|value| value.trim().to_string()) } pub async fn is_ancestor( @@ -201,10 +169,20 @@ impl Git { ) -> Result { reject_revision_arg(ancestor.as_str())?; reject_revision_arg(descendant.as_str())?; - self.local_backend - .clone() - .is_ancestor(self, repo_dir, ancestor, descendant) - .await + let output = self + .run( + Some(repo_dir), + [ + "rev-list", + "--max-count=1", + ancestor.as_str(), + "--not", + descendant.as_str(), + "--", + ], + ) + .await?; + Ok(output.stdout.iter().all(|byte| byte.is_ascii_whitespace())) } pub async fn for_each_ref_commits( @@ -213,10 +191,17 @@ impl Git { ref_prefix: &str, ) -> Result> { reject_ref_arg(ref_prefix, "ref prefix")?; - self.local_backend - .clone() - .for_each_ref_commits(self, repo_dir, ref_prefix) - .await + let output = self + .run( + Some(repo_dir), + ["for-each-ref", "--format=%(objectname)", "--", ref_prefix], + ) + .await?; + let text = output.stdout_utf8("for-each-ref")?; + text.lines() + .filter(|line| !line.trim().is_empty()) + .map(|line| CommitSha::parse(line.trim())) + .collect() } pub async fn for_each_ref( @@ -225,10 +210,32 @@ impl Git { ref_prefix: &str, ) -> Result> { reject_ref_arg(ref_prefix, "ref prefix")?; - self.local_backend - .clone() - .for_each_ref(self, repo_dir, ref_prefix) - .await + let output = self + .run( + Some(repo_dir), + [ + "for-each-ref", + "--format=%(refname) %(objectname)", + "--", + ref_prefix, + ], + ) + .await?; + let text = output.stdout_utf8("for-each-ref")?; + let mut refs = Vec::new(); + for line in text.lines() { + let line = line.trim(); + if line.is_empty() { + continue; + } + let Some((ref_name, commit)) = line.split_once(' ') else { + return Err(GitCacheError::Validation(format!( + "malformed git for-each-ref output line: {line:?}" + ))); + }; + refs.push((ref_name.to_string(), CommitSha::parse(commit)?)); + } + Ok(refs) } pub async fn for_each_ref_containing_commit( @@ -371,10 +378,36 @@ impl Git { for object_id in object_ids { reject_revision_arg(object_id.as_str())?; } - self.local_backend - .clone() - .cat_file_batch_types(self, repo_dir, object_ids) - .await + let mut stdin = Vec::with_capacity(object_ids.len() * 41); + for object_id in object_ids { + stdin.extend_from_slice(object_id.as_str().as_bytes()); + stdin.push(b'\n'); + } + + let output = self + .run_with_stdin_and_limits( + Some(repo_dir), + ["cat-file", "--batch-check=%(objectname) %(objecttype)"], + Some(&stdin), + self.output_limit, + self.output_limit, + ) + .await?; + let text = output.stdout_utf8("cat-file")?; + + let mut types = HashMap::new(); + for line in text.lines() { + let Some((object_id, object_type)) = line.split_once(' ') else { + return Err(GitCacheError::Validation(format!( + "malformed git cat-file output line: {line:?}" + ))); + }; + if object_type == "missing" { + continue; + } + types.insert(CommitSha::parse(object_id)?, object_type.to_string()); + } + Ok(types) } pub async fn cat_file_batch_types_no_lazy( diff --git a/crates/git-cache-git/tests/git_wrapper.rs b/crates/git-cache-git/tests/git_wrapper.rs index 5a6b619..2c212ee 100644 --- a/crates/git-cache-git/tests/git_wrapper.rs +++ b/crates/git-cache-git/tests/git_wrapper.rs @@ -373,76 +373,6 @@ mod tests { assert_eq!(second_containing, vec![second]); } - #[tokio::test] - async fn gitoxide_backend_matches_subprocess_backend() { - let temp = TempTree::new("gitoxide-parity"); - let (source_repo, first_sha) = create_source_repo(&temp.path); - let cache_repo = temp.path.join("cache.git"); - let gix = test_git().with_gitoxide(true); - let subprocess = test_git().with_gitoxide(false); - - let second_sha = commit_source(&source_repo, "second"); - gix.init_bare(&cache_repo).await.expect("init cache repo"); - gix.fetch_ref( - &cache_repo, - path_arg(&source_repo), - "refs/heads/main", - "refs/cache/upstream/heads/main", - FetchOptions::default(), - ) - .await - .expect("fetch cache ref"); - - for rev in ["refs/cache/upstream/heads/main", second_sha.as_str()] { - assert_eq!( - gix.rev_parse(&cache_repo, rev) - .await - .expect("gix rev-parse"), - subprocess - .rev_parse(&cache_repo, rev) - .await - .expect("subprocess rev-parse"), - ); - } - assert!(gix.rev_parse(&cache_repo, "refs/missing").await.is_err()); - - assert_eq!( - gix.for_each_ref(&cache_repo, "refs/cache/upstream/heads") - .await - .expect("gix for-each-ref"), - subprocess - .for_each_ref(&cache_repo, "refs/cache/upstream/heads") - .await - .expect("subprocess for-each-ref"), - ); - - let first = CommitSha::parse(&first_sha).unwrap(); - let second = CommitSha::parse(&second_sha).unwrap(); - for (ancestor, descendant) in [(&first, &second), (&second, &first), (&first, &first)] { - assert_eq!( - gix.is_ancestor(&cache_repo, ancestor, descendant) - .await - .expect("gix is-ancestor"), - subprocess - .is_ancestor(&cache_repo, ancestor, descendant) - .await - .expect("subprocess is-ancestor"), - ); - } - - let missing = CommitSha::parse("f".repeat(40)).unwrap(); - let ids = vec![first, second, missing]; - assert_eq!( - gix.cat_file_batch_types(&cache_repo, &ids) - .await - .expect("gix cat-file types"), - subprocess - .cat_file_batch_types(&cache_repo, &ids) - .await - .expect("subprocess cat-file types"), - ); - } - fn test_git() -> Git { Git::default_with_timeout(Duration::from_secs(10)) }