From ac04a82c7f7fadd842740d2b485ab398797d4394 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 15 Jul 2025 05:43:50 +0200 Subject: [PATCH 1/3] Upgrade gix to the latest version. This will fix an issue with submodules that couldn't be queried in an unborn repository. --- Cargo.lock | 214 ++++++++++++++++++++++++----------------------------- Cargo.toml | 4 +- 2 files changed, 99 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2eb4f2610b4..ceff47b22fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,18 +8,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -1258,9 +1246,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.72.1" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01237e8d3d78581f71642be8b0c2ae8c0b2b5c251c9c5d9ebbea3c1ea280dce8" +checksum = "514c29cc879bdc0286b0cbc205585a49b252809eb86c69df4ce4f855ee75f635" dependencies = [ "gix-actor", "gix-attributes", @@ -1312,9 +1300,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.35.1" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b300e6e4f31f3f6bd2de5e2b0caab192ced00dc0fcd0f7cc56e28c575c8e1ff" +checksum = "58ebbb8f41071c7cf318a0b1db667c34e1df49db7bf387d282a4e61a3b97882c" dependencies = [ "bstr", "gix-date", @@ -1326,9 +1314,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.26.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f50d813d5c2ce9463ba0c29eea90060df08e38ad8f34b8a192259f8bce5c078" +checksum = "45442188216d08a5959af195f659cb1f244a50d7d2d0c3873633b1cd7135f638" dependencies = [ "bstr", "gix-glob", @@ -1361,9 +1349,9 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05dd813ef6bb798570308aa7f1245cefa350ec9f30dc53308335eb22b9d0f8b" +checksum = "6b31b65ca48a352ae86312b27a514a0c661935f96b481ac8b4371f65815eb196" dependencies = [ "bstr", "gix-path", @@ -1374,9 +1362,9 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05050fd6caa6c731fe3bd7f9485b3b520be062d3d139cb2626e052d6c127951" +checksum = "6bb23121e952f43a5b07e3e80890336cb847297467a410475036242732980d06" dependencies = [ "bstr", "gix-chunk", @@ -1387,9 +1375,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f3c8f357ae049bfb77493c2ec9010f58cfc924ae485e1116c3718fc0f0d881" +checksum = "5dfb898c5b695fd4acfc3c0ab638525a65545d47706064dcf7b5ead6cdb136c0" dependencies = [ "bstr", "gix-config-value", @@ -1408,9 +1396,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439d62e241dae2dffd55bfeeabe551275cf9d9f084c5ebc6b48bad49d03285b7" +checksum = "9f012703eb67e263c6c1fc96649fec47694dd3e5d2a91abfc65e4a6a6dc85309" dependencies = [ "bitflags", "bstr", @@ -1421,13 +1409,14 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1c7307e36026b6088e5b12014ffe6d4f509c911ee453e22a7be4003a159c9b" +checksum = "0039dd3ac606dd80b16353a41b61fc237ca5cb8b612f67a9f880adfad4be4e05" dependencies = [ "bstr", "gix-command", "gix-config-value", + "gix-date", "gix-path", "gix-prompt", "gix-sec", @@ -1438,9 +1427,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139d1d52b21741e3f0c72b0fc65e1ff34d4eaceb100ef529d182725d2e09b8cb" +checksum = "d7235bdf4d9d54a6901928e3a37f91c16f419e6957f520ed929c3d292b84226e" dependencies = [ "bstr", "itoa 1.0.15", @@ -1451,9 +1440,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.52.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9b43e95fe352da82a969f0c84ff860c2de3e724d93f6681fedbcd6c917f252" +checksum = "de854852010d44a317f30c92d67a983e691c9478c8a3fb4117c1f48626bcdea8" dependencies = [ "bstr", "gix-hash", @@ -1463,9 +1452,9 @@ dependencies = [ [[package]] name = "gix-dir" -version = "0.14.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e6e2dc5b8917142d0ffe272209d1671e45b771e433f90186bc71c016792e87" +checksum = "dad34e4f373f94902df1ba1d2a1df3a1b29eacd15e316ac5972d842e31422dd7" dependencies = [ "bstr", "gix-discover", @@ -1483,9 +1472,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dccfe3e25b4ea46083916c56db3ba9d1e6ef6dce54da485f0463f9fc0fe1837c" +checksum = "ffb180c91ca1a2cf53e828bb63d8d8f8fa7526f49b83b33d7f46cbeb5d79d30a" dependencies = [ "bstr", "dunce", @@ -1499,9 +1488,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.42.1" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f4399af6ec4fd9db84dd4cf9656c5c785ab492ab40a7c27ea92b4241923fed" +checksum = "9a92748623c201568785ee69a561f4eec06f745b4fac67dab1d44ca9891a57ee" dependencies = [ "bytes", "crc32fast", @@ -1520,9 +1509,9 @@ dependencies = [ [[package]] name = "gix-filter" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecf004912949bbcf308d71aac4458321748ecb59f4d046830d25214208c471f1" +checksum = "aa6571a3927e7ab10f64279a088e0dae08e8da05547771796d7389bbe28ad9ff" dependencies = [ "bstr", "encoding_rs", @@ -1541,9 +1530,9 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a0637149b4ef24d3ea55f81f77231401c8463fae6da27331c987957eb597c7" +checksum = "d793f71e955d18f228d20ec433dcce6d0e8577efcdfd11d72d09d7cc2758dfd1" dependencies = [ "bstr", "fastrand", @@ -1555,9 +1544,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90181472925b587f6079698f79065ff64786e6d6c14089517a1972bca99fb6e9" +checksum = "b947db8366823e7a750c254f6bb29e27e17f27e457bf336ba79b32423db62cd5" dependencies = [ "bitflags", "bstr", @@ -1567,9 +1556,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4900562c662852a6b42e2ef03442eccebf24f047d8eab4f23bc12ef0d785d8" +checksum = "251fad79796a731a2a7664d9ea95ee29a9e99474de2769e152238d4fdb69d50e" dependencies = [ "faster-hex", "gix-features", @@ -1579,20 +1568,20 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b5cb3c308b4144f2612ff64e32130e641279fcf1a84d8d40dad843b4f64904" +checksum = "c35300b54896153e55d53f4180460931ccd69b7e8d2f6b9d6401122cdedc4f07" dependencies = [ "gix-hash", - "hashbrown 0.14.5", + "hashbrown", "parking_lot", ] [[package]] name = "gix-ignore" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae358c3c96660b10abc7da63c06788dfded603e717edbd19e38c6477911b71c8" +checksum = "564d6fddf46e2c981f571b23d6ad40cb08bddcaf6fc7458b1d49727ad23c2870" dependencies = [ "bstr", "gix-glob", @@ -1603,9 +1592,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38e919efd59cb8275d23ad2394b2ab9d002007b27620e145d866d546403b665" +checksum = "2af39fde3ce4ce11371d9ce826f2936ec347318f2d1972fe98c2e7134e267e25" dependencies = [ "bitflags", "bstr", @@ -1620,7 +1609,7 @@ dependencies = [ "gix-traverse", "gix-utils", "gix-validate", - "hashbrown 0.14.5", + "hashbrown", "itoa 1.0.15", "libc", "memmap2", @@ -1631,9 +1620,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "17.1.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570f8b034659f256366dc90f1a24924902f20acccd6a15be96d44d1269e7a796" +checksum = "b9fa71da90365668a621e184eb5b979904471af1b3b09b943a84bc50e8ad42ed" dependencies = [ "gix-tempfile", "gix-utils", @@ -1642,9 +1631,9 @@ dependencies = [ [[package]] name = "gix-negotiate" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e1ea901acc4d5b44553132a29e8697210cb0e739b2d9752d713072e9391e3c9" +checksum = "1d58d4c9118885233be971e0d7a589f5cfb1a8bd6cb6e2ecfb0fc6b1b293c83b" dependencies = [ "bitflags", "gix-commitgraph", @@ -1658,9 +1647,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.49.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d957ca3640c555d48bb27f8278c67169fa1380ed94f6452c5590742524c40fbb" +checksum = "49664e3e212bc34f7060f5738ce7022247e4afd959b68a4f666b1fd29c00b23c" dependencies = [ "bstr", "gix-actor", @@ -1679,9 +1668,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.69.1" +version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868f703905fdbcfc1bd750942f82419903ecb7039f5288adb5206d6de405e0c9" +checksum = "9c9d7af10fda9df0bb4f7f9bd507963560b3c66cb15a5b825caf752e0eb109ac" dependencies = [ "arc-swap", "gix-date", @@ -1700,9 +1689,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.59.1" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d49c55d69c8449f2a0a5a77eb9cbacfebb6b0e2f1215f0fc23a4cb60528a450" +checksum = "d8571df89bfca5abb49c3e3372393f7af7e6f8b8dbe2b96303593cef5b263019" dependencies = [ "clru", "gix-chunk", @@ -1720,9 +1709,9 @@ dependencies = [ [[package]] name = "gix-packetline" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddc034bc67c848e4ef7596ab5528cd8fd439d310858dbe1ce8b324f25deb91c" +checksum = "2592fbd36249a2fea11056f7055cc376301ef38d903d157de41998335bbf1f93" dependencies = [ "bstr", "faster-hex", @@ -1732,9 +1721,9 @@ dependencies = [ [[package]] name = "gix-packetline-blocking" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44880f028ba46d6cf37a66d27a300310c6b51b8ed0e44918f93df061168e2f3" +checksum = "fc4e706f328cd494cc8f932172e123a72b9a4711b0db5e411681432a89bd4c94" dependencies = [ "bstr", "faster-hex", @@ -1744,9 +1733,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.18" +version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567f65fec4ef10dfab97ae71f26a27fd4d7fe7b8e3f90c8a58551c41ff3fb65b" +checksum = "c6279d323d925ad4790602105ae27df4b915e7a7d81e4cdba2603121c03ad111" dependencies = [ "bstr", "gix-trace", @@ -1758,9 +1747,9 @@ dependencies = [ [[package]] name = "gix-pathspec" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce061c50e5f8f7c830cacb3da3e999ae935e283ce8522249f0ce2256d110979d" +checksum = "daedead611c9bd1f3640dc90a9012b45f790201788af4d659f28d94071da7fba" dependencies = [ "bitflags", "bstr", @@ -1773,9 +1762,9 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d024a3fe3993bbc17733396d2cefb169c7a9d14b5b71dafb7f96e3962b7c3128" +checksum = "6ffa1a7a34c81710aaa666a428c142b6c5d640492fcd41267db0740d923c7906" dependencies = [ "gix-command", "gix-config-value", @@ -1786,9 +1775,9 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.50.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c17d78bb0414f8d60b5f952196dc2e47ec320dca885de9128ecdb4a0e38401" +checksum = "12b4b807c47ffcf7c1e5b8119585368a56449f3493da93b931e1d4239364e922" dependencies = [ "bstr", "gix-credentials", @@ -1823,9 +1812,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.52.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1b7985657029684d759f656b09abc3e2c73085596d5cdb494428823970a7762" +checksum = "4b7a23209d4e4cbdc2086d294f5f3f8707ac6286768847024d952d8cd3278c5b" dependencies = [ "gix-actor", "gix-features", @@ -1844,9 +1833,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.30.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ed14e3db78e8e79980085e3723df94e1c8163b3ae5bc8ed6a8fe6cf983b42" +checksum = "7d29cae1ae31108826e7156a5e60bffacab405f4413f5bc0375e19772cce0055" dependencies = [ "bstr", "gix-hash", @@ -1858,9 +1847,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.34.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d0b8e5cbd1c329e25383e088cb8f17439414021a643b30afa5146b71e3c65d" +checksum = "f651f2b1742f760bb8161d6743229206e962b73d9c33c41f4e4aefa6586cbd3d" dependencies = [ "bitflags", "bstr", @@ -1876,9 +1865,9 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc756b73225bf005ddeb871d1ca7b3c33e2417d0d53e56effa5a36765b52b28" +checksum = "06e74f91709729e099af6721bd0fa7d62f243f2005085152301ca5cdd86ec02c" dependencies = [ "gix-commitgraph", "gix-date", @@ -1891,9 +1880,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dabbc78c759ecc006b970339394951b2c8e1e38a37b072c105b80b84c308fd" +checksum = "09f7053ed7c66633b56c57bc6ed3377be3166eaf3dc2df9f1c5ec446df6fdf2c" dependencies = [ "bitflags", "gix-path", @@ -1903,9 +1892,9 @@ dependencies = [ [[package]] name = "gix-shallow" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9a6f6e34d6ede08f522d89e5c7990b4f60524b8ae6ebf8e850963828119ad4" +checksum = "d936745103243ae4c510f19e0760ce73fb0f08096588fdbe0f0d7fb7ce8944b7" dependencies = [ "bstr", "gix-hash", @@ -1915,9 +1904,9 @@ dependencies = [ [[package]] name = "gix-submodule" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f51472f05a450cc61bc91ed2f62fb06e31e2bbb31c420bc4be8793f26c8b0c1" +checksum = "657cc5dd43cbc7a14d9c5aaf02cfbe9c2a15d077cded3f304adb30ef78852d3e" dependencies = [ "bstr", "gix-config", @@ -1930,9 +1919,9 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "17.1.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c750e8c008453a2dba67a2b0d928b7716e05da31173a3f5e351d5457ad4470aa" +checksum = "666c0041bcdedf5fa05e9bef663c897debab24b7dc1741605742412d1d47da57" dependencies = [ "gix-fs", "libc", @@ -1943,15 +1932,15 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c396a2036920c69695f760a65e7f2677267ccf483f25046977d87e4cb2665f7" +checksum = "e2ccaf54b0b1743a695b482ca0ab9d7603744d8d10b2e5d1a332fef337bee658" [[package]] name = "gix-transport" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe22ba26d4b65c17879f12b9882eafe65d3c8611c933b272fce2c10f546f59" +checksum = "12f7cc0179fc89d53c54e1f9ce51229494864ab4bf136132d69db1b011741ca3" dependencies = [ "base64", "bstr", @@ -1968,9 +1957,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.46.2" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8648172f85aca3d6e919c06504b7ac26baef54e04c55eb0100fa588c102cc33" +checksum = "c7cdc82509d792ba0ad815f86f6b469c7afe10f94362e96c4494525a6601bdd5" dependencies = [ "bitflags", "gix-commitgraph", @@ -1985,9 +1974,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a1ad0b04a5718b5cb233e6888e52a9b627846296161d81dcc5eb9203ec84b8" +checksum = "1b76a9d266254ad287ffd44467cd88e7868799b08f4d52e02d942b93e514d16f" dependencies = [ "bstr", "gix-features", @@ -2020,9 +2009,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f1916f8d928268300c977d773dd70a8746b646873b77add0a34876a8c847e9" +checksum = "55f625ac9126c19bef06dbc6d2703cdd7987e21e35b497bb265ac37d383877b1" dependencies = [ "bstr", "gix-attributes", @@ -2103,22 +2092,14 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", ] @@ -2128,7 +2109,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown", ] [[package]] @@ -2349,7 +2330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown", ] [[package]] @@ -3141,11 +3122,10 @@ dependencies = [ [[package]] name = "prodash" -version = "29.0.2" +version = "30.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04bb108f648884c23b98a0e940ebc2c93c0c3b89f04dbaf7eb8256ce617d1bc" +checksum = "5a6efc566849d3d9d737c5cb06cc50e48950ebe3d3f9d70631490fff3a07b139" dependencies = [ - "log", "parking_lot", ] diff --git a/Cargo.toml b/Cargo.toml index 7e849f18efc..ffde02ad020 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ flate2 = { version = "1.1.2", default-features = false, features = ["zlib-rs"] } git2 = "0.20.2" git2-curl = "0.21.0" # When updating this, also see if `gix-transport` further down needs updating or some auth-related tests will fail. -gix = { version = "0.72.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk"] } +gix = { version = "0.73.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk"] } glob = "0.3.2" # Pinned due to https://github.com/sunng87/handlebars-rust/issues/711 handlebars = { version = "=6.3.1", features = ["dir_source"] } @@ -257,7 +257,7 @@ cargo-test-support.workspace = true gix = { workspace = true, features = ["revision"] } # When building Cargo for tests, a safety-measure in `gix` needs to be disabled # to allow sending credentials over HTTP connections. -gix-transport = { version = "0.47.0", features = ["http-client-insecure-credentials"] } +gix-transport = { version = "0.48.0", features = ["http-client-insecure-credentials"] } same-file.workspace = true snapbox.workspace = true From d3b85cd96a76482e83caaa1f9e0c1fb2d788165c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 23 Jul 2025 04:36:07 +0200 Subject: [PATCH 2/3] Provide a `package` implementation with `gix-status`. This should also help fixing these spurious "cannot package because some excluded file is untracked" issues. Remove the respective `git2` implementation at the same time as there seems to be no need for it. --- Cargo.lock | 74 ++++++- Cargo.toml | 2 +- src/cargo/ops/cargo_package/mod.rs | 1 - src/cargo/ops/cargo_package/vcs.rs | 327 ++++++++++++++++++----------- tests/testsuite/git.rs | 6 +- tests/testsuite/package.rs | 15 +- 6 files changed, 284 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ceff47b22fa..88e829cefbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -892,6 +892,20 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "der" version = "0.7.10" @@ -1283,6 +1297,7 @@ dependencies = [ "gix-revwalk", "gix-sec", "gix-shallow", + "gix-status", "gix-submodule", "gix-tempfile", "gix-trace", @@ -1445,8 +1460,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de854852010d44a317f30c92d67a983e691c9478c8a3fb4117c1f48626bcdea8" dependencies = [ "bstr", + "gix-attributes", + "gix-command", + "gix-filter", + "gix-fs", "gix-hash", + "gix-index", "gix-object", + "gix-path", + "gix-pathspec", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-worktree", + "imara-diff", "thiserror 2.0.12", ] @@ -1573,7 +1600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c35300b54896153e55d53f4180460931ccd69b7e8d2f6b9d6401122cdedc4f07" dependencies = [ "gix-hash", - "hashbrown", + "hashbrown 0.15.4", "parking_lot", ] @@ -1609,7 +1636,7 @@ dependencies = [ "gix-traverse", "gix-utils", "gix-validate", - "hashbrown", + "hashbrown 0.15.4", "itoa 1.0.15", "libc", "memmap2", @@ -1902,6 +1929,29 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "gix-status" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4afff9b34eeececa8bdc32b42fb318434b6b1391d9f8d45fe455af08dc2d35" +dependencies = [ + "bstr", + "filetime", + "gix-diff", + "gix-dir", + "gix-features", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-worktree", + "portable-atomic", + "thiserror 2.0.12", +] + [[package]] name = "gix-submodule" version = "0.20.0" @@ -1923,6 +1973,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "666c0041bcdedf5fa05e9bef663c897debab24b7dc1741605742412d1d47da57" dependencies = [ + "dashmap", "gix-fs", "libc", "once_cell", @@ -2092,6 +2143,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.4" @@ -2109,7 +2166,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown", + "hashbrown 0.15.4", ] [[package]] @@ -2323,6 +2380,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "imara-diff" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" +dependencies = [ + "hashbrown 0.15.4", +] + [[package]] name = "indexmap" version = "2.10.0" @@ -2330,7 +2396,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.4", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ffde02ad020..3e573091ef9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ flate2 = { version = "1.1.2", default-features = false, features = ["zlib-rs"] } git2 = "0.20.2" git2-curl = "0.21.0" # When updating this, also see if `gix-transport` further down needs updating or some auth-related tests will fail. -gix = { version = "0.73.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk"] } +gix = { version = "0.73.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk", "status"] } glob = "0.3.2" # Pinned due to https://github.com/sunng87/handlebars-rust/issues/711 handlebars = { version = "=6.3.1", features = ["dir_source"] } diff --git a/src/cargo/ops/cargo_package/mod.rs b/src/cargo/ops/cargo_package/mod.rs index 4692339390d..3aa0babbd1c 100644 --- a/src/cargo/ops/cargo_package/mod.rs +++ b/src/cargo/ops/cargo_package/mod.rs @@ -480,7 +480,6 @@ fn prepare_archive( // Check (git) repository state, getting the current commit hash. let vcs_info = vcs::check_repo_state(pkg, &src_files, ws, &opts)?; - build_ar_list(ws, pkg, src_files, vcs_info, opts.include_lockfile) } diff --git a/src/cargo/ops/cargo_package/vcs.rs b/src/cargo/ops/cargo_package/vcs.rs index 09107abf35e..cbc899a4fce 100644 --- a/src/cargo/ops/cargo_package/vcs.rs +++ b/src/cargo/ops/cargo_package/vcs.rs @@ -1,22 +1,20 @@ //! Helpers to gather the VCS information for `cargo package`. - -use std::collections::HashSet; -use std::path::Path; -use std::path::PathBuf; - -use anyhow::Context as _; +use crate::core::{Package, Workspace}; +use crate::ops::PackageOpts; +use crate::sources::PathEntry; +use crate::{CargoResult, GlobalContext}; +use anyhow::Context; use cargo_util::paths; +use gix::bstr::ByteSlice; +use gix::dir::walk::EmissionMode; +use gix::index::entry::Mode; +use gix::status::tree_index::TrackRenames; +use gix::worktree::stack::state::ignore::Source; use serde::Serialize; +use std::collections::HashSet; +use std::path::{Path, PathBuf}; use tracing::debug; -use crate::CargoResult; -use crate::GlobalContext; -use crate::core::Package; -use crate::core::Workspace; -use crate::sources::PathEntry; - -use super::PackageOpts; - /// Represents the VCS information when packaging. #[derive(Serialize)] pub struct VcsInfo { @@ -29,7 +27,7 @@ pub struct VcsInfo { #[derive(Serialize)] pub struct GitVcsInfo { sha1: String, - /// Indicate whether or not the Git worktree is dirty. + /// Indicate whether the Git worktree is dirty. #[serde(skip_serializing_if = "std::ops::Not::not")] dirty: bool, } @@ -39,7 +37,7 @@ pub struct GitVcsInfo { /// If *git*, and the source is *dirty* (e.g., has uncommitted changes), /// and `--allow-dirty` has not been passed, /// then `bail!` with an informative message. -/// Otherwise return the sha1 hash of the current *HEAD* commit, +/// Otherwise, return the sha1 hash of the current *HEAD* commit, /// or `None` if no repo is found. #[tracing::instrument(skip_all)] pub fn check_repo_state( @@ -49,7 +47,7 @@ pub fn check_repo_state( opts: &PackageOpts<'_>, ) -> CargoResult> { let gctx = ws.gctx(); - let Ok(repo) = git2::Repository::discover(p.root()) else { + let Ok(repo) = gix::discover(p.root()) else { gctx.shell().verbose(|shell| { shell.warn(format_args!( "no (git) VCS found for `{}`", @@ -71,21 +69,33 @@ pub fn check_repo_state( debug!("found a git repo at `{}`", workdir.display()); let path = p.manifest_path(); + + let manifest_exists = path.exists(); let path = paths::strip_prefix_canonical(path, workdir).unwrap_or_else(|_| path.to_path_buf()); - let Ok(status) = repo.status_file(&path) else { + let rela_path = + gix::path::to_unix_separators_on_windows(gix::path::os_str_into_bstr(path.as_os_str())?); + if !manifest_exists { gctx.shell().verbose(|shell| { shell.warn(format_args!( - "no (git) Cargo.toml found at `{}` in workdir `{}`", + "Cargo.toml not found at `{}` in workdir `{}`", path.display(), workdir.display() )) })?; - // No checked-in `Cargo.toml` found. This package may be irrelevant. + // No `Cargo.toml` found. This package may be irrelevant. // Have to assume it is clean. return Ok(None); }; - if !(status & git2::Status::IGNORED).is_empty() { + let manifest_is_ignored = { + let index = repo.index_or_empty()?; + let mut excludes = + repo.excludes(&index, None, Source::WorktreeThenIdMappingIfNotSkipped)?; + excludes + .at_entry(rela_path.as_bstr(), Some(Mode::FILE))? + .is_excluded() + }; + if manifest_is_ignored { gctx.shell().verbose(|shell| { shell.warn(format_args!( "found (git) Cargo.toml ignored at `{}` in workdir `{}`", @@ -106,7 +116,7 @@ pub fn check_repo_state( workdir.display(), ); let Some(git) = git(ws, p, src_files, &repo, &opts)? else { - // If the git repo lacks essensial field like `sha1`, and since this field exists from the beginning, + // If the git repo lacks essential field like `sha1`, and since this field exists from the beginning, // then don't generate the corresponding file in order to maintain consistency with past behavior. return Ok(None); }; @@ -117,7 +127,7 @@ pub fn check_repo_state( .unwrap_or("") .replace("\\", "/"); - return Ok(Some(VcsInfo { git, path_in_vcs })); + Ok(Some(VcsInfo { git, path_in_vcs })) } /// Warns if any symlinks were checked out as plain text files. @@ -136,11 +146,11 @@ pub fn check_repo_state( fn warn_symlink_checked_out_as_plain_text_file( gctx: &GlobalContext, src_files: &[PathEntry], - repo: &git2::Repository, + repo: &gix::Repository, ) -> CargoResult<()> { if repo - .config() - .and_then(|c| c.get_bool("core.symlinks")) + .config_snapshot() + .boolean(&gix::config::tree::Core::SYMLINKS) .unwrap_or(true) { return Ok(()); @@ -149,8 +159,8 @@ fn warn_symlink_checked_out_as_plain_text_file( if src_files.iter().any(|f| f.maybe_plain_text_symlink()) { let mut shell = gctx.shell(); shell.warn(format_args!( - "found symbolic links that may be checked out as regular files for git repo at `{}`\n\ - This might cause the `.crate` file to include incorrect or incomplete files", + "found symbolic links that may be checked out as regular files for git repo at `{}/`\n\ + This might cause the `.crate` file to include incorrect or incomplete files", repo.workdir().unwrap().display(), ))?; let extra_note = if cfg!(windows) { @@ -171,7 +181,7 @@ fn git( ws: &Workspace<'_>, pkg: &Package, src_files: &[PathEntry], - repo: &git2::Repository, + repo: &gix::Repository, opts: &PackageOpts<'_>, ) -> CargoResult> { // This is a collection of any dirty or untracked files. This covers: @@ -179,13 +189,23 @@ fn git( // - untracked files (which are "new" worktree files) // - ignored (in case the user has an `include` directive that // conflicts with .gitignore). - let mut dirty_files = Vec::new(); - let pathspec = relative_pathspec(repo, pkg.root()); - collect_statuses(repo, &[pathspec.as_str()], &mut dirty_files)?; + let (mut dirty_files, mut dirty_files_outside_package_root) = (Vec::new(), Vec::new()); + let workdir = repo.workdir().unwrap(); + collect_statuses( + repo, + workdir, + relative_package_root(repo, pkg.root()).as_deref(), + &mut dirty_files, + &mut dirty_files_outside_package_root, + )?; // Include each submodule so that the error message can provide // specifically *which* files in a submodule are modified. - status_submodules(repo, &mut dirty_files)?; + status_submodules( + repo, + &mut dirty_files, + &mut dirty_files_outside_package_root, + )?; // Find the intersection of dirty in git, and the src_files that would // be packaged. This is a lazy n^2 check, but seems fine with @@ -193,9 +213,27 @@ fn git( let cwd = ws.gctx().cwd(); let mut dirty_src_files: Vec<_> = src_files .iter() - .filter(|src_file| dirty_files.iter().any(|path| src_file.starts_with(path))) + .filter(|src_file| { + if let Some(canon_src_file) = src_file.is_symlink_or_under_symlink().then(|| { + gix::path::realpath_opts( + &src_file, + ws.gctx().cwd(), + gix::path::realpath::MAX_SYMLINKS, + ) + .unwrap_or_else(|_| src_file.to_path_buf()) + }) { + dirty_files + .iter() + .any(|path| canon_src_file.starts_with(path)) + } else { + dirty_files.iter().any(|path| src_file.starts_with(path)) + } + }) .map(|p| p.as_ref()) - .chain(dirty_files_outside_pkg_root(ws, pkg, repo, src_files)?.iter()) + .chain( + dirty_files_outside_pkg_root(ws, pkg, &dirty_files_outside_package_root, src_files)? + .iter(), + ) .map(|path| { pathdiff::diff_paths(path, cwd) .as_ref() @@ -206,14 +244,9 @@ fn git( .collect(); let dirty = !dirty_src_files.is_empty(); if !dirty || opts.allow_dirty { - // Must check whetherthe repo has no commit firstly, otherwise `revparse_single` would fail on bare commit repo. - // Due to lacking the `sha1` field, it's better not record the `GitVcsInfo` for consistency. - if repo.is_empty()? { - return Ok(None); - } - let rev_obj = repo.revparse_single("HEAD")?; - Ok(Some(GitVcsInfo { - sha1: rev_obj.id().to_string(), + let maybe_head_id = repo.head()?.try_peel_to_id_in_place()?; + Ok(maybe_head_id.map(|id| GitVcsInfo { + sha1: id.to_string(), dirty, })) } else { @@ -228,6 +261,114 @@ fn git( } } +/// Helper to collect dirty statuses for a single repo. +/// `relative_package_root` is `Some` if the root is a sub-directory of the workdir. +/// Writes dirty files outside `relative_package_root` into `dirty_files_outside_package_root`, +/// and all *everything else* into `dirty_files`. +#[must_use] +fn collect_statuses( + repo: &gix::Repository, + workdir: &Path, + relative_package_root: Option<&Path>, + dirty_files: &mut Vec, + dirty_files_outside_package_root: &mut Vec, +) -> CargoResult<()> { + let statuses = repo + .status(gix::progress::Discard)? + .dirwalk_options(|opts| { + opts.emit_untracked(gix::dir::walk::EmissionMode::Matching) + // Also pick up ignored files or whole directories + // to specifically catch overzealously ignored source files. + // Later we will match these dirs by prefix, which is why collapsing + // them is desirable here. + .emit_ignored(Some(EmissionMode::CollapseDirectory)) + .emit_tracked(false) + .recurse_repositories(false) + .symlinks_to_directories_are_ignored_like_directories(true) + .emit_empty_directories(false) + }) + .tree_index_track_renames(TrackRenames::Disabled) + .index_worktree_submodules(None) + .into_iter(None /* pathspec patterns */) + .with_context(|| { + format!( + "failed to begin git status for repo {}", + repo.path().display() + ) + })?; + + for status in statuses { + let status = status.with_context(|| { + format!( + "failed to retrieve git status from repo {}", + repo.path().display() + ) + })?; + + let rel_path = gix::path::from_bstr(status.location()); + let path = workdir.join(&rel_path); + if relative_package_root.is_some_and(|pkg_root| !rel_path.starts_with(pkg_root)) { + dirty_files_outside_package_root.push(path); + continue; + } + + // It is OK to include Cargo.lock even if it is ignored. + if path.ends_with("Cargo.lock") + && matches!( + &status, + gix::status::Item::IndexWorktree( + gix::status::index_worktree::Item::DirectoryContents { entry, .. } + ) if matches!(entry.status, gix::dir::entry::Status::Ignored(_)) + ) + { + continue; + } + + dirty_files.push(path); + } + Ok(()) +} + +/// Helper to collect dirty statuses while recursing into submodules. +fn status_submodules( + repo: &gix::Repository, + dirty_files: &mut Vec, + dirty_files_outside_package_root: &mut Vec, +) -> CargoResult<()> { + let Some(submodules) = repo.submodules()? else { + return Ok(()); + }; + for submodule in submodules { + // Ignore submodules that don't open, they are probably not initialized. + // If its files are required, then the verification step should fail. + if let Some(sub_repo) = submodule.open()? { + let Some(workdir) = sub_repo.workdir() else { + continue; + }; + status_submodules(&sub_repo, dirty_files, dirty_files_outside_package_root)?; + collect_statuses( + &sub_repo, + workdir, + None, + dirty_files, + dirty_files_outside_package_root, + )?; + } + } + Ok(()) +} + +/// Make `pkg_root` relative to the `repo` workdir. +fn relative_package_root(repo: &gix::Repository, pkg_root: &Path) -> Option { + let workdir = repo.workdir().unwrap(); + let rela_root = pkg_root.strip_prefix(workdir).unwrap_or(Path::new("")); + if rela_root.as_os_str().is_empty() { + None + } else { + rela_root.to_owned().into() + } +} + /// Checks whether "included" source files outside package root have been modified. /// /// This currently looks at @@ -242,14 +383,10 @@ fn git( fn dirty_files_outside_pkg_root( ws: &Workspace<'_>, pkg: &Package, - repo: &git2::Repository, + dirty_files_outside_of_package_root: &[PathBuf], src_files: &[PathEntry], ) -> CargoResult> { let pkg_root = pkg.root(); - let workdir = repo.workdir().unwrap(); - - let mut dirty_files = HashSet::new(); - let meta = pkg.manifest().metadata(); let metadata_paths: Vec<_> = [&meta.license_file, &meta.readme] .into_iter() @@ -257,7 +394,7 @@ fn dirty_files_outside_pkg_root( .map(|path| paths::normalize_path(&pkg_root.join(path))) .collect(); - for rel_path in src_files + let dirty_files = src_files .iter() .filter(|p| p.is_symlink_or_under_symlink()) .map(|p| p.as_ref().as_path()) @@ -266,83 +403,19 @@ fn dirty_files_outside_pkg_root( // If inside package root. Don't bother checking git status. .filter(|p| paths::strip_prefix_canonical(p, pkg_root).is_err()) // Handle files outside package root but under git workdir, - .filter_map(|p| paths::strip_prefix_canonical(p, workdir).ok()) - { - match repo.status_file(&rel_path) { - Ok(git2::Status::CURRENT) => {} - Ok(_) => { - dirty_files.insert(workdir.join(rel_path)); - } - Err(e) => { - // Dirtiness check for symlinks is mostly informational. - // And changes in submodule would fail git-status as well (see #15384). - // To avoid adding complicated logic to handle that, - // for now we ignore the status check failure. - debug!( - "failed to get status from file `{}` in git repo at `{}`: {e}", - rel_path.display(), - workdir.display() - ); - } - } - } - Ok(dirty_files) -} + .filter_map(|src_file| { + let canon_src_path = gix::path::realpath_opts( + src_file, + ws.gctx().cwd(), + gix::path::realpath::MAX_SYMLINKS, + ) + .unwrap_or_else(|_| src_file.to_owned()); -/// Helper to collect dirty statuses for a single repo. -fn collect_statuses( - repo: &git2::Repository, - pathspecs: &[&str], - dirty_files: &mut Vec, -) -> CargoResult<()> { - let mut status_opts = git2::StatusOptions::new(); - // Exclude submodules, as they are being handled manually by recursing - // into each one so that details about specific files can be - // retrieved. - pathspecs - .iter() - .fold(&mut status_opts, git2::StatusOptions::pathspec) - .exclude_submodules(true) - .include_ignored(true) - .include_untracked(true); - let repo_statuses = repo.statuses(Some(&mut status_opts)).with_context(|| { - format!( - "failed to retrieve git status from repo {}", - repo.path().display() - ) - })?; - let workdir = repo.workdir().unwrap(); - let this_dirty = repo_statuses.iter().filter_map(|entry| { - let path = entry.path().expect("valid utf-8 path"); - if path.ends_with("Cargo.lock") && entry.status() == git2::Status::IGNORED { - // It is OK to include Cargo.lock even if it is ignored. - return None; - } - // Use an absolute path, so that comparing paths is easier - // (particularly with submodules). - Some(workdir.join(path)) - }); - dirty_files.extend(this_dirty); - Ok(()) -} - -/// Helper to collect dirty statuses while recursing into submodules. -fn status_submodules(repo: &git2::Repository, dirty_files: &mut Vec) -> CargoResult<()> { - for submodule in repo.submodules()? { - // Ignore submodules that don't open, they are probably not initialized. - // If its files are required, then the verification step should fail. - if let Ok(sub_repo) = submodule.open() { - status_submodules(&sub_repo, dirty_files)?; - collect_statuses(&sub_repo, &[], dirty_files)?; - } - } - Ok(()) -} - -/// Use pathspec so git only matches a certain path prefix -fn relative_pathspec(repo: &git2::Repository, pkg_root: &Path) -> String { - let workdir = repo.workdir().unwrap(); - let relpath = pkg_root.strip_prefix(workdir).unwrap_or(Path::new("")); - // to unix separators - relpath.to_str().unwrap().replace('\\', "/") + dirty_files_outside_of_package_root + .iter() + .any(|p| canon_src_path.starts_with(p)) + .then_some(canon_src_path) + }) + .collect(); + Ok(dirty_files) } diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index cd86c8f0ec6..52fecb3a83f 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -3162,9 +3162,10 @@ fn dirty_submodule() { .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. -[ERROR] 1 files in the working directory contain changes that were not yet committed into git: +[ERROR] 2 files in the working directory contain changes that were not yet committed into git: .gitmodules +src/lib.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag @@ -3208,9 +3209,10 @@ to proceed despite this and include the uncommitted changes, pass the `--allow-d .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. -[ERROR] 1 files in the working directory contain changes that were not yet committed into git: +[ERROR] 2 files in the working directory contain changes that were not yet committed into git: src/.gitmodules +src/bar/mod.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index b3669244bcd..a0577f65a9a 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -1347,7 +1347,7 @@ fn dirty_file_outside_pkg_root_considered_dirty() { git::commit(&repo); // Changing files outside pkg root under situations below should be treated - // as dirty. `cargo package` is expected to fail on VCS stastus check. + // as dirty. `cargo package` is expected to fail on VCS status check. // // * Changes in files outside package root that source files symlink to p.change_file("README.md", "after"); @@ -1355,7 +1355,7 @@ fn dirty_file_outside_pkg_root_considered_dirty() { p.change_file("original-dir/file", "after"); // * Changes in files outside pkg root that `license-file`/`readme` point to p.change_file("LICENSE", "after"); - // * When workspace root manifest has changned, + // * When workspace root manifest has changed, // no matter whether workspace inheritance is involved. p.change_file( "Cargo.toml", @@ -1367,7 +1367,7 @@ fn dirty_file_outside_pkg_root_considered_dirty() { edition = "2021" "#, ); - // Changes in files outside git workdir won't affect vcs status check + // Changes in files outside git workdir won't affect VCS status check p.change_file( &main_outside_pkg_root, r#"fn main() { eprintln!("after"); }"#, @@ -1470,13 +1470,16 @@ fn dirty_file_outside_pkg_root_inside_submodule() { p.symlink("submodule/file.txt", "isengard/src/file.txt"); git::add(&repo); git::commit(&repo); - // This dirtyness should be detected in the future. p.change_file("submodule/file.txt", "changed"); p.cargo("package --workspace --no-verify") + .with_status(101) .with_stderr_data(str![[r#" -[PACKAGING] isengard v0.0.0 ([ROOT]/foo/isengard) -[PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[ERROR] 1 files in the working directory contain changes that were not yet committed into git: + +isengard/src/file.txt + +to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); From dfe3737634655a675373a9e281334c4dd2a3e2bc Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 18 Jul 2025 05:43:03 +0200 Subject: [PATCH 3/3] Optimize performance of `cargo package`. This is achieved by allowing `gix status` to only run in the package root, while running it another time just on the few files that are interesting outside of the package root. This saves a lot of time compared to the previous implementation, which ran the status on the entire repository. --- src/cargo/ops/cargo_package/vcs.rs | 143 ++++++++++++++++------------- 1 file changed, 80 insertions(+), 63 deletions(-) diff --git a/src/cargo/ops/cargo_package/vcs.rs b/src/cargo/ops/cargo_package/vcs.rs index cbc899a4fce..9692828ad34 100644 --- a/src/cargo/ops/cargo_package/vcs.rs +++ b/src/cargo/ops/cargo_package/vcs.rs @@ -1,4 +1,5 @@ //! Helpers to gather the VCS information for `cargo package`. + use crate::core::{Package, Workspace}; use crate::ops::PackageOpts; use crate::sources::PathEntry; @@ -7,11 +8,11 @@ use anyhow::Context; use cargo_util::paths; use gix::bstr::ByteSlice; use gix::dir::walk::EmissionMode; +use gix::dirwalk::Options; use gix::index::entry::Mode; use gix::status::tree_index::TrackRenames; use gix::worktree::stack::state::ignore::Source; use serde::Serialize; -use std::collections::HashSet; use std::path::{Path, PathBuf}; use tracing::debug; @@ -47,7 +48,7 @@ pub fn check_repo_state( opts: &PackageOpts<'_>, ) -> CargoResult> { let gctx = ws.gctx(); - let Ok(repo) = gix::discover(p.root()) else { + let Ok(mut repo) = gix::discover(p.root()) else { gctx.shell().verbose(|shell| { shell.warn(format_args!( "no (git) VCS found for `{}`", @@ -115,7 +116,7 @@ pub fn check_repo_state( path.display(), workdir.display(), ); - let Some(git) = git(ws, p, src_files, &repo, &opts)? else { + let Some(git) = git(ws, p, src_files, &mut repo, &opts)? else { // If the git repo lacks essential field like `sha1`, and since this field exists from the beginning, // then don't generate the corresponding file in order to maintain consistency with past behavior. return Ok(None); @@ -181,31 +182,32 @@ fn git( ws: &Workspace<'_>, pkg: &Package, src_files: &[PathEntry], - repo: &gix::Repository, + repo: &mut gix::Repository, opts: &PackageOpts<'_>, ) -> CargoResult> { + { + let mut config = repo.config_snapshot_mut(); + // This currently is only a very minor speedup for the biggest repositories, + // but might trigger creating many threads. + config.set_value(&gix::config::tree::Index::THREADS, "false")?; + } // This is a collection of any dirty or untracked files. This covers: // - new/modified/deleted/renamed/type change (index or worktree) // - untracked files (which are "new" worktree files) // - ignored (in case the user has an `include` directive that // conflicts with .gitignore). - let (mut dirty_files, mut dirty_files_outside_package_root) = (Vec::new(), Vec::new()); + let mut dirty_files = Vec::new(); let workdir = repo.workdir().unwrap(); collect_statuses( repo, workdir, relative_package_root(repo, pkg.root()).as_deref(), &mut dirty_files, - &mut dirty_files_outside_package_root, )?; // Include each submodule so that the error message can provide // specifically *which* files in a submodule are modified. - status_submodules( - repo, - &mut dirty_files, - &mut dirty_files_outside_package_root, - )?; + status_submodules(repo, &mut dirty_files)?; // Find the intersection of dirty in git, and the src_files that would // be packaged. This is a lazy n^2 check, but seems fine with @@ -230,10 +232,7 @@ fn git( } }) .map(|p| p.as_ref()) - .chain( - dirty_files_outside_pkg_root(ws, pkg, &dirty_files_outside_package_root, src_files)? - .iter(), - ) + .chain(dirty_files_outside_pkg_root(ws, pkg, repo, src_files)?.iter()) .map(|path| { pathdiff::diff_paths(path, cwd) .as_ref() @@ -271,25 +270,17 @@ fn collect_statuses( workdir: &Path, relative_package_root: Option<&Path>, dirty_files: &mut Vec, - dirty_files_outside_package_root: &mut Vec, ) -> CargoResult<()> { let statuses = repo .status(gix::progress::Discard)? - .dirwalk_options(|opts| { - opts.emit_untracked(gix::dir::walk::EmissionMode::Matching) - // Also pick up ignored files or whole directories - // to specifically catch overzealously ignored source files. - // Later we will match these dirs by prefix, which is why collapsing - // them is desirable here. - .emit_ignored(Some(EmissionMode::CollapseDirectory)) - .emit_tracked(false) - .recurse_repositories(false) - .symlinks_to_directories_are_ignored_like_directories(true) - .emit_empty_directories(false) - }) + .dirwalk_options(configure_dirwalk) .tree_index_track_renames(TrackRenames::Disabled) .index_worktree_submodules(None) - .into_iter(None /* pathspec patterns */) + .into_iter( + relative_package_root.map(|rela_pkg_root| { + gix::path::into_bstr(rela_pkg_root).into_owned() + }), /* pathspec patterns */ + ) .with_context(|| { format!( "failed to begin git status for repo {}", @@ -307,11 +298,6 @@ fn collect_statuses( let rel_path = gix::path::from_bstr(status.location()); let path = workdir.join(&rel_path); - if relative_package_root.is_some_and(|pkg_root| !rel_path.starts_with(pkg_root)) { - dirty_files_outside_package_root.push(path); - continue; - } - // It is OK to include Cargo.lock even if it is ignored. if path.ends_with("Cargo.lock") && matches!( @@ -330,11 +316,7 @@ fn collect_statuses( } /// Helper to collect dirty statuses while recursing into submodules. -fn status_submodules( - repo: &gix::Repository, - dirty_files: &mut Vec, - dirty_files_outside_package_root: &mut Vec, -) -> CargoResult<()> { +fn status_submodules(repo: &gix::Repository, dirty_files: &mut Vec) -> CargoResult<()> { let Some(submodules) = repo.submodules()? else { return Ok(()); }; @@ -345,14 +327,8 @@ fn status_submodules( let Some(workdir) = sub_repo.workdir() else { continue; }; - status_submodules(&sub_repo, dirty_files, dirty_files_outside_package_root)?; - collect_statuses( - &sub_repo, - workdir, - None, - dirty_files, - dirty_files_outside_package_root, - )?; + status_submodules(&sub_repo, dirty_files)?; + collect_statuses(&sub_repo, workdir, None, dirty_files)?; } } Ok(()) @@ -374,7 +350,7 @@ fn relative_package_root(repo: &gix::Repository, pkg_root: &Path) -> Option Option, pkg: &Package, - dirty_files_outside_of_package_root: &[PathBuf], + repo: &gix::Repository, src_files: &[PathEntry], -) -> CargoResult> { +) -> CargoResult> { let pkg_root = pkg.root(); + let workdir = repo.workdir().unwrap(); + let meta = pkg.manifest().metadata(); let metadata_paths: Vec<_> = [&meta.license_file, &meta.readme] .into_iter() @@ -394,7 +372,7 @@ fn dirty_files_outside_pkg_root( .map(|path| paths::normalize_path(&pkg_root.join(path))) .collect(); - let dirty_files = src_files + let linked_files_outside_package_root: Vec<_> = src_files .iter() .filter(|p| p.is_symlink_or_under_symlink()) .map(|p| p.as_ref().as_path()) @@ -403,19 +381,58 @@ fn dirty_files_outside_pkg_root( // If inside package root. Don't bother checking git status. .filter(|p| paths::strip_prefix_canonical(p, pkg_root).is_err()) // Handle files outside package root but under git workdir, - .filter_map(|src_file| { - let canon_src_path = gix::path::realpath_opts( - src_file, - ws.gctx().cwd(), - gix::path::realpath::MAX_SYMLINKS, + .filter_map(|p| paths::strip_prefix_canonical(p, workdir).ok()) + .collect(); + + if linked_files_outside_package_root.is_empty() { + return Ok(Vec::new()); + } + + let statuses = repo + .status(gix::progress::Discard)? + .dirwalk_options(configure_dirwalk) + // Limit the amount of threads for used for the worktree status, as the pathspec will + // prevent most paths from being visited anyway there is not much work. + .index_worktree_options_mut(|opts| opts.thread_limit = Some(1)) + .tree_index_track_renames(TrackRenames::Disabled) + .index_worktree_submodules(None) + .into_iter( + linked_files_outside_package_root + .into_iter() + .map(|p| gix::path::into_bstr(p).into_owned()), + ) + .with_context(|| { + format!( + "failed to begin git status for outfor repo {}", + repo.path().display() ) - .unwrap_or_else(|_| src_file.to_owned()); + })?; - dirty_files_outside_of_package_root - .iter() - .any(|p| canon_src_path.starts_with(p)) - .then_some(canon_src_path) - }) - .collect(); + let mut dirty_files = Vec::new(); + for status in statuses { + let status = status.with_context(|| { + format!( + "failed to retrieve git status from repo {}", + repo.path().display() + ) + })?; + + let rel_path = gix::path::from_bstr(status.location()); + let path = workdir.join(&rel_path); + dirty_files.push(path); + } Ok(dirty_files) } + +fn configure_dirwalk(opts: Options) -> Options { + opts.emit_untracked(gix::dir::walk::EmissionMode::Matching) + // Also pick up ignored files or whole directories + // to specifically catch overzealously ignored source files. + // Later we will match these dirs by prefix, which is why collapsing + // them is desirable here. + .emit_ignored(Some(EmissionMode::CollapseDirectory)) + .emit_tracked(false) + .recurse_repositories(false) + .symlinks_to_directories_are_ignored_like_directories(true) + .emit_empty_directories(false) +}