diff --git a/Cargo.lock b/Cargo.lock index abc7213..75176a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -31,24 +31,24 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -94,9 +94,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "assert-json-diff" @@ -110,15 +116,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -149,9 +155,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -170,15 +176,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" dependencies = [ "jobserver", "libc", @@ -190,6 +196,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "charset" version = "0.1.3" @@ -212,9 +224,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -222,9 +234,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -234,14 +246,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -296,9 +308,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -374,6 +386,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -407,9 +430,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "encode_unicode" @@ -419,9 +442,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -444,9 +467,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "filetime" @@ -504,21 +527,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.30" @@ -526,7 +534,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -535,34 +542,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-sink" version = "0.3.30" @@ -581,16 +560,10 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -605,9 +578,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -622,11 +595,11 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "libgit2-sys", "log", @@ -657,9 +630,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -691,10 +664,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.3.5" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "home" @@ -705,34 +678,11 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hoot" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df22a4d90f1b0e65fe3e0d6ee6a4608cc4d81f4b2eb3e670f44bb6bde711e452" -dependencies = [ - "httparse", - "log", -] - -[[package]] -name = "hootbin" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354e60868e49ea1a39c44b9562ad207c4259dc6eabf9863bf3b0f058c55cfdb2" -dependencies = [ - "fastrand", - "hoot", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -779,7 +729,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", "tokio", "tower-service", "tracing", @@ -798,9 +747,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -821,9 +770,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "install-wheel-rs" @@ -840,6 +789,7 @@ dependencies = [ "indoc", "mailparse", "once_cell", + "pep508_rs", "platform-info", "plist", "pyo3", @@ -867,17 +817,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2" dependencies = [ "libc", ] @@ -910,23 +869,22 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.5", ] [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -945,9 +903,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" dependencies = [ "cc", "libc", @@ -957,12 +915,9 @@ dependencies = [ [[package]] name = "line-wrap" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] +checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" [[package]] name = "linux-raw-sys" @@ -982,9 +937,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "value-bag", ] @@ -1012,15 +967,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1036,9 +991,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -1047,13 +1002,13 @@ dependencies = [ [[package]] name = "mockito" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8d3038e23466858569c2d30a537f691fa0d53b51626630ae08262943e3bbb8b" +checksum = "d2f6e023aa5bdf392aa06c78e4a4e6d498baab5138d0c993503350ebbc37bf1e" dependencies = [ "assert-json-diff", "colored", - "futures", + "futures-core", "hyper", "log", "rand", @@ -1079,6 +1034,7 @@ dependencies = [ "indicatif", "indoc", "install-wheel-rs", + "itertools", "libc", "libloading", "libz-sys", @@ -1137,12 +1093,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -1162,16 +1119,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "number_prefix" version = "0.4.0" @@ -1201,18 +1148,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.2.2+3.2.1" +version = "300.2.3+3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfad0063610ac26ee79f7484739e2b07555a75c42453b89263830b5c8103bc" +checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -1258,30 +1205,35 @@ dependencies = [ [[package]] name = "pep440_rs" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c29f9c43de378b4e4e0cd7dbcce0e5cfb80443de8c05620368b2948bc936a1" +checksum = "ca0a570e7ec9171250cac57614e901f62408094b54b3798bb920d3cf0d4a0e09" dependencies = [ "once_cell", - "regex", + "pyo3", "serde", + "tracing", "unicode-width", + "unscanny", ] [[package]] name = "pep508_rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910c513bea0f4f833122321c0f20e8c704e01de98692f6989c2ec21f43d88b1e" +version = "0.4.2" +source = "git+https://github.com/konstin/pep508_rs?rev=e5dea4d041a2a7863074a60b667d04989ba84dcc#e5dea4d041a2a7863074a60b667d04989ba84dcc" dependencies = [ + "derivative", "once_cell", "pep440_rs", + "pyo3", + "pyo3-log", "regex", "serde", "thiserror", "tracing", "unicode-width", "url", + "urlencoding", ] [[package]] @@ -1292,9 +1244,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1304,9 +1256,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -1316,9 +1268,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "platform-info" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6259c4860e53bf665016f1b2f46a8859cadfa717581dc9d597ae4069de6300f" +checksum = "d5ff316b9c4642feda973c18f0decd6c8b0919d4722566f6e4337cce0dd88217" dependencies = [ "libc", "winapi", @@ -1326,9 +1278,9 @@ dependencies = [ [[package]] name = "plist" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" +checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" dependencies = [ "base64 0.21.7", "indexmap", @@ -1358,9 +1310,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1376,15 +1328,16 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.20.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89dc7a5850d0e983be1ec2a463a171d20990487c3cfcd68b5363f1ee3d6fe0" +checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -1393,9 +1346,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07426f0d8fe5a601f26293f300afd1a7b1ed5e78b2a705870c5f30893c5163be" +checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" dependencies = [ "once_cell", "target-lexicon", @@ -1403,36 +1356,47 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb7dec17e17766b46bca4f1a4215a85006b4c2ecde122076c562dd058da6cf1" +checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" dependencies = [ "libc", "pyo3-build-config", ] +[[package]] +name = "pyo3-log" +version = "0.9.0" +source = "git+https://github.com/a1phyr/pyo3-log?rev=76ff388163dd1100eb70ba164d59a42795829bdb#76ff388163dd1100eb70ba164d59a42795829bdb" +dependencies = [ + "arc-swap", + "log", + "pyo3", +] + [[package]] name = "pyo3-macros" -version = "0.20.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f738b4e40d50b5711957f142878cfa0f28e054aa0ebdfc3fd137a843f74ed3" +checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn", + "syn 2.0.60", ] [[package]] name = "pyo3-macros-backend" -version = "0.20.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc910d4851847827daf9d6cdd4a823fbdaab5b8818325c5e97a86da79e8881f" +checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", + "pyo3-build-config", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -1446,9 +1410,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1491,9 +1455,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1520,9 +1484,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -1531,9 +1495,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1543,9 +1507,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1554,15 +1518,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rfc2047-decoder" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e372613f15fc5171f9052b0c1fbafca5b1e5b0ba86aa13c9c39fd91ca1f7955" +checksum = "e90a668c463c412c3118ae1883e18b53d812c349f5af7a06de3ba4bb0c17cc73" dependencies = [ "base64 0.21.7", "charset", @@ -1574,16 +1538,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1594,11 +1559,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1607,9 +1572,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" dependencies = [ "log", "ring", @@ -1621,9 +1586,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" [[package]] name = "rustls-webpki" @@ -1638,15 +1603,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "safemem" -version = "0.3.3" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -1680,34 +1639,34 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] name = "serde" -version = "1.0.196" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -1755,20 +1714,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "similar" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" [[package]] name = "slab" @@ -1781,18 +1731,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1816,9 +1766,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1828,9 +1778,20 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1850,15 +1811,15 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.13" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -1868,29 +1829,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -1898,9 +1859,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -1919,9 +1880,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -1944,34 +1905,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", - "tokio-macros", "windows-sys 0.48.0", ] -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tokio-util" version = "0.7.10" @@ -1988,9 +1935,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", @@ -2009,9 +1956,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.4" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ "indexmap", "serde", @@ -2046,7 +1993,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -2110,9 +2057,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -2143,13 +2090,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.5" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b52731d03d6bb2fd18289d4028aee361d6c28d44977846793b994b13cdcc64d" +checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" dependencies = [ "base64 0.21.7", "flate2", - "hootbin", "log", "once_cell", "rustls", @@ -2173,6 +2119,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8parse" version = "0.2.1" @@ -2187,9 +2139,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" +checksum = "74797339c3b98616c009c7c3eb53a0ce41e85c8ec66bd3db96ed132d20cfdee8" [[package]] name = "vcpkg" @@ -2205,9 +2157,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2239,22 +2191,21 @@ dependencies = [ [[package]] name = "which" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" +checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" dependencies = [ "either", "home", - "once_cell", "rustix", - "windows-sys 0.52.0", + "winsafe", ] [[package]] name = "widestring" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "winapi" @@ -2302,7 +2253,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -2322,17 +2273,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2343,9 +2295,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2355,9 +2307,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2367,9 +2319,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2379,9 +2337,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2391,9 +2349,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2403,9 +2361,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2415,19 +2373,25 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.5.39" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "xattr" version = "1.3.1" @@ -2456,7 +2420,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -2479,27 +2443,27 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 6df7368..61dc5cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,32 +3,36 @@ members = ["crates/*"] resolver = "2" [workspace.dependencies] -anyhow = "1.0.75" -cpufeatures = "0.2.11" -fs-err = "2.9.0" +anyhow = "1.0.81" +cpufeatures = "0.2.12" +fs-err = "2.11.0" fs2 = "0.4.3" -indoc = "2.0.4" +indoc = "2.0.5" logtest = "2.0.0" -mockito = "1.2.0" -pep508_rs = { version = "0.3.0", features = ["serde"] } -pyo3 = { version = "0.20.2", features = ["extension-module", "abi3-py37"] } -regex = "1.9.5" -serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" -sha2 = "0.10.7" +mockito = "1.4.0" +pep508_rs = { version = "0.4.2", features = ["serde"] } +pyo3 = { version = "0.21.2", features = ["extension-module", "abi3-py38"] } +regex = "1.10.4" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" +sha2 = "0.10.8" tar = "0.4.40" -target-lexicon = "0.12.11" -tempfile = "3.8.0" -thiserror = "1.0.48" -toml = "0.8.0" -tracing = "0.1.37" -tracing-subscriber = "0.3.17" +target-lexicon = "0.12.14" +tempfile = "3.10.1" +thiserror = "1.0.58" +toml = "0.8.12" +tracing = { version = "0.1.40", features = ["log"] } +tracing-subscriber = "0.3.18" unscanny = "0.1.0" -ureq = { version = "2.7.1", features = ["json"] } -walkdir = "2.4.0" -which = "6.0.0" +ureq = { version = "2.9.6", features = ["json"] } +walkdir = "2.5.0" +which = "6.0.1" widestring = "1.0.2" -zstd = "0.13.0" +zstd = "0.13.1" + +[patch.crates-io] +pep508_rs = { git = "https://github.com/konstin/pep508_rs", rev = "e5dea4d041a2a7863074a60b667d04989ba84dcc" } +pyo3-log = { git = "https://github.com/a1phyr/pyo3-log", rev = "76ff388163dd1100eb70ba164d59a42795829bdb" } # Config for 'cargo dist' [workspace.metadata.dist] diff --git a/crates/install-wheel-rs/Cargo.toml b/crates/install-wheel-rs/Cargo.toml index d19f8c8..6d9fbe1 100644 --- a/crates/install-wheel-rs/Cargo.toml +++ b/crates/install-wheel-rs/Cargo.toml @@ -13,26 +13,27 @@ name = "install_wheel_rs" #crate-type = ["cdylib", "rlib"] [dependencies] -clap = { version = "4.4.6", optional = true, features = ["derive", "env"] } -configparser = "3.0.2" -csv = "1.2.2" -data-encoding = "2.4.0" +clap = { version = "4.5.4", optional = true, features = ["derive", "env"] } +configparser = "3.0.4" +csv = "1.3.0" +data-encoding = "2.5.0" fs-err = { workspace = true } fs2 = { workspace = true } glibc_version = "0.1.2" goblin = "0.8.0" -mailparse = "0.14.0" -once_cell = "1.18.0" +mailparse = "0.14.1" +once_cell = "1.19.0" +pep508_rs = { workspace = true } platform-info = "2.0.2" -plist = "1.5.0" -pyo3 = { workspace = true, features = ["extension-module", "abi3-py37"], optional = true } -rayon = { version = "1.8.0", optional = true } +plist = "1.6.1" +pyo3 = { workspace = true, features = ["extension-module", "abi3-py38"], optional = true } +rayon = { version = "1.10.0", optional = true } regex = { workspace = true } -rfc2047-decoder = "1.0.1" +rfc2047-decoder = "1.0.5" serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } sha2 = { workspace = true } -target-lexicon = "0.12.11" +target-lexicon = "0.12.14" tempfile = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } @@ -42,7 +43,7 @@ zip = { version = "0.6.6", default-features = false, features = ["deflate"] } # [features] default = ["cli", "parallel"] -python_bindings = ["pyo3", "tracing-subscriber"] +pyo3 = ["dep:pyo3", "tracing-subscriber"] cli = ["clap"] parallel = ["rayon"] diff --git a/crates/install-wheel-rs/pyproject.toml b/crates/install-wheel-rs/pyproject.toml index b81f0f2..74ed8be 100644 --- a/crates/install-wheel-rs/pyproject.toml +++ b/crates/install-wheel-rs/pyproject.toml @@ -2,7 +2,7 @@ name = "install-wheel-rs" [tool.maturin] -features = ["python_bindings"] +features = ["pyo3"] [build-system] requires = ["maturin>=1.2,<2.0"] diff --git a/crates/install-wheel-rs/src/install_location.rs b/crates/install-wheel-rs/src/install_location.rs index 29fade9..6a28215 100644 --- a/crates/install-wheel-rs/src/install_location.rs +++ b/crates/install-wheel-rs/src/install_location.rs @@ -10,16 +10,6 @@ use tracing::{error, warn}; const INSTALL_LOCKFILE: &str = "install-wheel-rs.lock"; -/// I'm not sure that's the right way to normalize here, but it's a single place to change -/// everything. -/// -/// For displaying to the user, `-` is better, and it's also what poetry lockfile 2.0 does -/// -/// Keep in sync with `find_distributions` -pub fn normalize_name(dep_name: &str) -> String { - dep_name.to_lowercase().replace(['.', '_'], "-") -} - /// A directory for which we acquired a install-wheel-rs.lock lockfile pub struct LockedDir { /// The directory to lock diff --git a/crates/install-wheel-rs/src/lib.rs b/crates/install-wheel-rs/src/lib.rs index c73020d..450653a 100644 --- a/crates/install-wheel-rs/src/lib.rs +++ b/crates/install-wheel-rs/src/lib.rs @@ -12,6 +12,7 @@ //! ).unwrap(); //! ``` +use pep508_rs::InvalidNameError; use platform_info::PlatformInfoError; use std::fs::File; use std::io; @@ -20,7 +21,7 @@ use std::str::FromStr; use thiserror::Error; use zip::result::ZipError; -pub use install_location::{normalize_name, InstallLocation, LockedDir}; +pub use install_location::{InstallLocation, LockedDir}; pub use wheel::{ get_script_launcher, install_wheel, parse_key_value_file, read_record_file, relative_to, Script, SHEBANG_PYTHON, @@ -28,7 +29,7 @@ pub use wheel::{ pub use wheel_tags::{Arch, CompatibleTags, Os, WheelFilename}; mod install_location; -#[cfg(feature = "python_bindings")] +#[cfg(feature = "pyo3")] mod python_bindings; mod wheel; mod wheel_tags; @@ -70,6 +71,8 @@ pub enum Error { PlatformInfo(#[source] PlatformInfoError), #[error("Invalid version specification, only none or == is supported")] Pep440, + #[error("Wheel has an unsupported package name")] + InvalidNameError(#[from] InvalidNameError), } impl Error { diff --git a/crates/install-wheel-rs/src/python_bindings.rs b/crates/install-wheel-rs/src/python_bindings.rs index edaa206..fd72271 100644 --- a/crates/install-wheel-rs/src/python_bindings.rs +++ b/crates/install-wheel-rs/src/python_bindings.rs @@ -2,8 +2,9 @@ use crate::{install_wheel, CompatibleTags, Error, InstallLocation, LockedDir, WheelFilename}; use pyo3::create_exception; +use pyo3::prelude::PyAnyMethods; use pyo3::types::PyModule; -use pyo3::{pyclass, pymethods, pymodule, PyErr, PyResult, Python}; +use pyo3::{pyclass, pymethods, pymodule, Bound, PyErr, PyResult, Python}; use std::env; use std::fs::File; use std::path::{Path, PathBuf}; @@ -47,7 +48,7 @@ impl LockedVenv { pub fn install_wheel(&self, py: Python, wheel: PathBuf) -> PyResult<()> { // Would be nicer through https://docs.python.org/3/c-api/init.html#c.Py_GetProgramFullPath - let sys_executable: String = py.import("sys")?.getattr("executable")?.extract()?; + let sys_executable: String = py.import_bound("sys")?.getattr("executable")?.extract()?; // TODO: Pass those options on to the user py.allow_threads(|| { @@ -76,7 +77,7 @@ impl LockedVenv { } #[pymodule] -pub fn install_wheel_rs(_py: Python, m: &PyModule) -> PyResult<()> { +pub fn install_wheel_rs(_py: Python, m: &Bound) -> PyResult<()> { // Good enough for now if env::var_os("RUST_LOG").is_some() { tracing_subscriber::fmt::init(); diff --git a/crates/install-wheel-rs/src/wheel.rs b/crates/install-wheel-rs/src/wheel.rs index bf623b5..1e8229b 100644 --- a/crates/install-wheel-rs/src/wheel.rs +++ b/crates/install-wheel-rs/src/wheel.rs @@ -2,12 +2,13 @@ use crate::install_location::{InstallLocation, LockedDir}; use crate::wheel_tags::WheelFilename; -use crate::{normalize_name, Error}; +use crate::Error; use configparser::ini::Ini; use data_encoding::BASE64URL_NOPAD; use fs_err as fs; use fs_err::{DirEntry, File}; use mailparse::MailHeaderMap; +use pep508_rs::{ExtraName, PackageName}; use regex::Regex; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -16,6 +17,7 @@ use std::ffi::OsString; use std::io::{BufRead, BufReader, BufWriter, Cursor, Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; +use std::str::FromStr; use std::{env, io, iter}; use tempfile::{tempdir, TempDir}; use tracing::{debug, error, span, warn, Level}; @@ -58,7 +60,7 @@ struct DirectUrl { /// A script defining the name of the runnable entrypoint and the module and function that should be /// run. -#[cfg(feature = "python_bindings")] +#[cfg(feature = "pyo3")] #[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[pyo3::pyclass(dict)] pub struct Script { @@ -72,7 +74,7 @@ pub struct Script { /// A script defining the name of the runnable entrypoint and the module and function that should be /// run. -#[cfg(not(feature = "python_bindings"))] +#[cfg(not(feature = "pyo3"))] #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct Script { pub script_name: String, @@ -533,7 +535,7 @@ fn bytecode_compile( python_version: (u8, u8), sys_executable: &Path, // Only for logging - name: &str, + name: &PackageName, record: &mut Vec, ) -> Result<(), Error> { // https://github.com/pypa/pip/blob/b5457dfee47dd9e9f6ec45159d9d410ba44e5ea1/src/pip/_internal/operations/install/wheel.py#L592-L603 @@ -829,7 +831,7 @@ fn install_data( venv_base: &Path, site_packages: &Path, data_dir: &Path, - dist_name: &str, + dist_name: &PackageName, location: &InstallLocation, console_scripts: &[Script], gui_scripts: &[Script], @@ -875,7 +877,7 @@ fn install_data( location.get_python_version().0, location.get_python_version().1 )) - .join(dist_name); + .join(dist_name.to_string()); move_folder_recorded(&data_entry.path(), &target_path, site_packages, record)?; } Some("purelib" | "platlib") => { @@ -1019,19 +1021,17 @@ pub fn install_wheel( check_hashes: bool, // initially used to the console scripts, currently unused. Keeping it because we likely need // it for validation later - _extras: &[String], + _extras: &[ExtraName], unique_version: &str, sys_executable: impl AsRef, ) -> Result { let name = &filename.distribution; - let _my_span = span!(Level::DEBUG, "install_wheel", name = name.as_str()); + let _my_span = span!(Level::DEBUG, "install_wheel", name = %name); let (temp_dir_final_location, base_location) = match location { InstallLocation::Venv { venv_base, .. } => (None, venv_base.to_path_buf()), InstallLocation::Monotrail { monotrail_root, .. } => { - let name_version_dir = monotrail_root - .join(normalize_name(name)) - .join(unique_version); + let name_version_dir = monotrail_root.join(name.to_string()).join(unique_version); fs::create_dir_all(&name_version_dir)?; let final_location = name_version_dir.join(filename.get_tag()); // temp dir and rename for atomicity @@ -1070,12 +1070,12 @@ pub fn install_wheel( .join("site-packages") }; - debug!(name = name.as_str(), "Opening zip"); + debug!(name = %name, "Opening zip"); // No BufReader: https://github.com/zip-rs/zip/issues/381 let mut archive = ZipArchive::new(reader).map_err(|err| Error::from_zip_error("(index)".to_string(), err))?; - debug!(name = name.as_str(), "Getting wheel metadata"); + debug!(name = %name, "Getting wheel metadata"); let dist_info_prefix = find_dist_info(&filename, &mut archive)?; let (name, _version) = read_metadata(&dist_info_prefix, &mut archive)?; // TODO: Check that name and version match @@ -1101,7 +1101,7 @@ pub fn install_wheel( // > 1.c If Root-Is-Purelib == ‘true’, unpack archive into purelib (site-packages). // > 1.d Else unpack archive into platlib (site-packages). // We always install in the same virtualenv site packages - debug!(name = name.as_str(), "Extracting file"); + debug!(name = %name, "Extracting file"); let unpacked_paths = unpack_wheel_files( &site_packages, &record_path, @@ -1110,12 +1110,12 @@ pub fn install_wheel( check_hashes, )?; debug!( - name = name.as_str(), + name = %name, "Extracted {} files", unpacked_paths.len() ); - debug!(name = name.as_str(), "Writing entrypoints"); + debug!(name = %name, "Writing entrypoints"); let (console_scripts, gui_scripts) = parse_scripts(&mut archive, &dist_info_prefix, None)?; write_script_entrypoints(&site_packages, &location, &console_scripts, &mut record)?; write_script_entrypoints(&site_packages, &location, &gui_scripts, &mut record)?; @@ -1124,7 +1124,7 @@ pub fn install_wheel( // 2.a Unpacked archive includes distribution-1.0.dist-info/ and (if there is data) distribution-1.0.data/. // 2.b Move each subtree of distribution-1.0.data/ onto its destination path. Each subdirectory of distribution-1.0.data/ is a key into a dict of destination directories, such as distribution-1.0.data/(purelib|platlib|headers|scripts|data). The initially supported paths are taken from distutils.command.install. if data_dir.is_dir() { - debug!(name = name.as_str(), "Installing data"); + debug!(name = %name, "Installing data"); install_data( &base_location, &site_packages, @@ -1142,27 +1142,27 @@ pub fn install_wheel( // 2.e Remove empty distribution-1.0.data directory. fs::remove_dir_all(data_dir)?; } else { - debug!(name = name.as_str(), "No data"); + debug!(name = %name, "No data"); } // 2.f Compile any installed .py to .pyc. (Uninstallers should be smart enough to remove .pyc even if it is not mentioned in RECORD.) if compile { - debug!(name = name.as_str(), "Bytecode compiling"); + debug!(name = %name, "Bytecode compiling"); bytecode_compile( &site_packages, unpacked_paths, location.get_python_version(), sys_executable.as_ref(), - name.as_str(), + &name, &mut record, )?; } - debug!(name = name.as_str(), "Writing extra metadata"); + debug!(name = %name, "Writing extra metadata"); extra_dist_info(&site_packages, &dist_info_prefix, true, &mut record)?; - debug!(name = name.as_str(), "Writing record"); + debug!(name = %name, "Writing record"); let mut record_writer = csv::WriterBuilder::new() .has_headers(false) .escape(b'"') @@ -1190,8 +1190,12 @@ fn find_dist_info( filename: &WheelFilename, archive: &mut ZipArchive, ) -> Result { - let dist_info_matcher = - format!("{}-{}", filename.distribution, filename.version).to_lowercase(); + let dist_info_matcher = format!( + "{}-{}", + filename.distribution.to_string().replace('-', "_"), + filename.version + ) + .to_lowercase(); let dist_infos: Vec<_> = archive .file_names() .filter_map(|name| name.split_once('/')) @@ -1220,7 +1224,7 @@ fn find_dist_info( fn read_metadata( dist_info_prefix: &str, archive: &mut ZipArchive, -) -> Result<(String, String), Error> { +) -> Result<(PackageName, String), Error> { let mut content = Vec::new(); let metadata_file = format!("{dist_info_prefix}.dist-info/METADATA"); archive @@ -1249,12 +1253,9 @@ fn read_metadata( metadata_version ))); } - let name = headers - .get_first_value("Name") - .ok_or(Error::InvalidWheel(format!( - "No Name field in {}", - metadata_file - )))?; + let name = PackageName::from_str(&headers.get_first_value("Name").ok_or( + Error::InvalidWheel(format!("No Name field in {}", metadata_file)), + )?)?; let version = headers .get_first_value("Version") .ok_or(Error::InvalidWheel(format!( diff --git a/crates/install-wheel-rs/src/wheel_tags.rs b/crates/install-wheel-rs/src/wheel_tags.rs index b4a06ec..2dd2d34 100644 --- a/crates/install-wheel-rs/src/wheel_tags.rs +++ b/crates/install-wheel-rs/src/wheel_tags.rs @@ -4,6 +4,7 @@ use crate::Error; use fs_err as fs; use goblin::elf::Elf; use once_cell::sync::Lazy; +use pep508_rs::PackageName; use platform_info::{PlatformInfo, PlatformInfoAPI, UNameAPI}; use regex::Regex; use serde::Deserialize; @@ -20,11 +21,12 @@ use tracing::trace; /// /// ``` /// use std::str::FromStr; +/// use pep508_rs::PackageName; /// use install_wheel_rs::WheelFilename; /// /// let filename = WheelFilename::from_str("foo-1.0-py32-none-any.whl").unwrap(); /// assert_eq!(filename, WheelFilename { -/// distribution: "foo".to_string(), +/// distribution: PackageName::from_str("foo").unwrap(), /// version: "1.0".to_string(), /// python_tag: vec!["py32".to_string()], /// abi_tag: vec!["none".to_string()], @@ -34,7 +36,7 @@ use tracing::trace; /// "numpy-1.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" /// ).unwrap(); /// assert_eq!(filename, WheelFilename { -/// distribution: "numpy".to_string(), +/// distribution: PackageName::from_str("numpy").unwrap(), /// version: "1.26.0".to_string(), /// python_tag: vec!["cp312".to_string()], /// abi_tag: vec!["cp312".to_string()], @@ -46,7 +48,7 @@ use tracing::trace; /// ``` #[derive(Debug, Clone, Eq, PartialEq)] pub struct WheelFilename { - pub distribution: String, + pub distribution: PackageName, pub version: String, pub python_tag: Vec, pub abi_tag: Vec, @@ -65,7 +67,7 @@ impl FromStr for WheelFilename { // TODO: Build tag precedence &[distribution, version, _, python_tag, abi_tag, platform_tag] | &[distribution, version, python_tag, abi_tag, platform_tag] => Ok(WheelFilename { - distribution: distribution.to_string(), + distribution: PackageName::from_str(distribution)?, version: version.to_string(), python_tag: python_tag.split('.').map(String::from).collect(), abi_tag: abi_tag.split('.').map(String::from).collect(), diff --git a/crates/monotrail/Cargo.toml b/crates/monotrail/Cargo.toml index 055e305..cb908ef 100644 --- a/crates/monotrail/Cargo.toml +++ b/crates/monotrail/Cargo.toml @@ -10,24 +10,25 @@ name = "monotrail" [dependencies] anyhow = { workspace = true } -clap = { version = "4.4.4", features = ["derive"] } +clap = { version = "4.5.4", features = ["derive"] } cpufeatures = { workspace = true } -data-encoding = "2.4.0" +data-encoding = "2.5.0" dirs = "5.0.1" fs-err = { workspace = true } fs2 = { workspace = true } -git2 = "0.18.1" -indicatif = "0.17.7" +git2 = "0.18.3" +indicatif = "0.17.8" install-wheel-rs = { version = "0.0.1", path = "../install-wheel-rs" } -libc = "0.2.148" -libloading = "0.8.0" -libz-sys = { version = "1.1.12", features = ["static"] } # For the zig build +itertools = "0.12.1" +libc = "0.2.153" +libloading = "0.8.3" +libz-sys = { version = "1.1.16", features = ["static"] } # For the zig build monotrail-utils = { version = "0.0.1", path = "../monotrail-utils" } -nix = { version = "0.27.1", features = ["process"] } -pep440_rs = "0.4.0" +nix = { version = "0.28.0", features = ["process"] } +pep440_rs = "0.6.0" pep508_rs = { workspace = true, features = ["serde"] } -pyo3 = { workspace = true, features = ["extension-module", "abi3-py37"], optional = true } -rayon = "1.8.0" +pyo3 = { workspace = true, features = ["extension-module", "abi3-py38"], optional = true } +rayon = "1.10.0" regex = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } @@ -54,7 +55,7 @@ which = { workspace = true } [features] default = ["vendored"] -python_bindings = ["pyo3", "install-wheel-rs/python_bindings"] +pyo3 = ["dep:pyo3", "install-wheel-rs/pyo3", "pep508_rs/pyo3"] vendored = ["git2/vendored-openssl", "git2/vendored-libgit2"] diff --git a/crates/monotrail/src/cli.rs b/crates/monotrail/src/cli.rs index b2089f8..7768c90 100644 --- a/crates/monotrail/src/cli.rs +++ b/crates/monotrail/src/cli.rs @@ -16,9 +16,8 @@ use install_wheel_rs::{CompatibleTags, Error, InstallLocation}; use monotrail_utils::parse_cpython_args::parse_plus_arg; use monotrail_utils::RequirementsTxt; use pep440_rs::Operator; -use pep508_rs::VersionOrUrl; +use pep508_rs::{ExtraName, PackageName, VersionOrUrl}; use std::env; -use std::env::current_dir; use std::path::{Path, PathBuf}; use std::process::Command; use tracing::{debug, info}; @@ -30,7 +29,7 @@ pub struct PoetryOptions { no_dev: bool, /// The extras for which the dependencies should be installed #[clap(long, short = 'E')] - extras: Vec, + extras: Vec, /// Whether to install in a venv or the monotrail cache #[clap(long)] monotrail: bool, @@ -81,7 +80,7 @@ pub enum Cli { Run { /// Install those extras from pyproject.toml #[clap(long, short = 'E')] - extras: Vec, + extras: Vec, /// Run this python version x.y. If you pass multiple versions it will run one after /// the other, just like tox #[clap(long, short)] @@ -98,7 +97,7 @@ pub enum Cli { Ppipx { /// name of the pypi package that contains the command #[clap(long)] - package: Option, + package: Option, /// Run this python version x.y #[clap(long, short)] python_version: Option, @@ -107,7 +106,7 @@ pub enum Cli { version: Option, /// extras to enable on the package e.g. `jupyter` for `black` to get `black[jupyter]` #[clap(long)] - extras: Vec, + extras: Vec, /// This contains first the command to run (e.g. `black` or `pytest`), which will also be /// used as package name unless --package is set, and then the arguments to be passed /// verbatim to the command. This is just `args` and not `command` and `args` due to @@ -123,7 +122,7 @@ pub enum Cli { revision: String, /// extras to enable on the package e.g. `jupyter` for `black` to get `black[jupyter]` #[clap(long)] - extras: Vec, + extras: Vec, /// Run this python version x.y #[clap(long, short)] python_version: Option, @@ -182,12 +181,15 @@ pub enum Cli { /// Builds cache filename, downloads if not present, returns cache filename pub fn download_distribution_cached( - name: &str, + name: &PackageName, version: &str, filename: &str, url: &str, ) -> anyhow::Result { - let target_dir = cache_dir()?.join("artifacts").join(name).join(version); + let target_dir = cache_dir()? + .join("artifacts") + .join(name.to_string()) + .join(version); let target_file = target_dir.join(filename); if target_file.is_file() { @@ -288,7 +290,7 @@ pub fn install( } let venv = find_venv(venv)?; let working_dir = match working_dir { - None => current_dir().context("Couldn't get current directory ಠ_ಠ")?, + None => env::current_dir().context("Couldn't get current directory ಠ_ಠ")?, Some(working_dir) => working_dir.to_path_buf(), }; let python_version = get_venv_python_version(&venv)?; @@ -451,7 +453,7 @@ pub fn run_cli(cli: Cli, venv: Option<&Path>) -> anyhow::Result> { extras, args, } => Ok(Some(ppipx::ppipx( - package.as_deref(), + package.as_ref(), python_version.as_deref(), version.as_deref(), &extras, diff --git a/crates/monotrail/src/get_pep508_env.py b/crates/monotrail/src/get_pep508_env.py index 7c72cdc..40c634c 100644 --- a/crates/monotrail/src/get_pep508_env.py +++ b/crates/monotrail/src/get_pep508_env.py @@ -3,6 +3,7 @@ passes the values back to rust as json """ + import json import os import platform diff --git a/crates/monotrail/src/inject_and_run.rs b/crates/monotrail/src/inject_and_run.rs index d7d7d4b..b2420a7 100644 --- a/crates/monotrail/src/inject_and_run.rs +++ b/crates/monotrail/src/inject_and_run.rs @@ -9,6 +9,7 @@ use install_wheel_rs::{get_script_launcher, Script, SHEBANG_PYTHON}; use libc::{c_int, c_void, wchar_t}; use libloading::Library; use monotrail_utils::parse_cpython_args::{determine_python_version, naive_python_arg_parser}; +use pep508_rs::ExtraName; use std::collections::BTreeMap; use std::env; use std::env::current_exe; @@ -282,7 +283,7 @@ pub fn run_python_args( args: &[String], python_version: Option<&str>, root: Option<&Path>, - extras: &[String], + extras: &[ExtraName], ) -> anyhow::Result { let (args, python_version) = determine_python_version(args, python_version, DEFAULT_PYTHON_VERSION)?; diff --git a/crates/monotrail/src/install.rs b/crates/monotrail/src/install.rs index 179003c..be63ee3 100644 --- a/crates/monotrail/src/install.rs +++ b/crates/monotrail/src/install.rs @@ -11,9 +11,10 @@ use fs_err::{DirEntry, File}; use git2::{Direction, Repository}; use indicatif::{ProgressBar, ProgressStyle}; use install_wheel_rs::{ - install_wheel, normalize_name, parse_key_value_file, CompatibleTags, InstallLocation, - LockedDir, WheelFilename, + install_wheel, parse_key_value_file, CompatibleTags, InstallLocation, LockedDir, WheelFilename, }; +use itertools::Itertools; +use pep508_rs::PackageName; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use serde::Serialize; use std::io; @@ -27,10 +28,10 @@ use tempfile::TempDir; use tracing::{debug, info, trace, warn}; /// what we communicate back to python -#[cfg_attr(feature = "python_bindings", pyo3::pyclass(get_all))] +#[cfg_attr(feature = "pyo3", pyo3::pyclass)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct InstalledPackage { - pub name: String, + pub name: PackageName, pub python_version: String, pub unique_version: String, /// The compatibility tag like "py3-none-any" or @@ -38,12 +39,12 @@ pub struct InstalledPackage { pub tag: String, } -#[cfg_attr(feature = "python_bindings", pyo3::pymethods)] +#[cfg_attr(feature = "pyo3", pyo3::pymethods)] impl InstalledPackage { /// PathBuf for pyo3 pub fn monotrail_location(&self, sprawl_root: PathBuf) -> PathBuf { sprawl_root - .join(&self.name) + .join(self.name.to_string()) .join(&self.unique_version) .join(&self.tag) } @@ -66,6 +67,30 @@ impl InstalledPackage { .join("site-packages") } } + + #[cfg(feature = "pyo3")] + #[getter] + fn name(&self) -> String { + self.name.to_string() + } + + #[cfg(feature = "pyo3")] + #[getter] + fn python_version(&self) -> &str { + &self.python_version + } + + #[cfg(feature = "pyo3")] + #[getter] + fn unique_version(&self) -> &str { + &self.unique_version + } + + #[cfg(feature = "pyo3")] + #[getter] + fn tag(&self) -> &str { + &self.tag + } } /// Reads the installed packages through .dist-info/WHEEL files, returns the set that is installed @@ -93,7 +118,7 @@ pub fn filter_installed_venv( .filter_map(|entry| { let filename = entry.file_name().to_string_lossy().to_string(); let (name, version) = filename.strip_suffix(".dist-info")?.split_once('-')?; - let name = normalize_name(&name.to_lowercase()); + let name = PackageName::from_str(name).ok()?; Some((entry, name, version.to_string())) }) .map(|(entry, name, version)| { @@ -189,7 +214,7 @@ pub fn install_all( start.elapsed().as_secs_f32() ); let installed_package = InstalledPackage { - name: spec.normalized_name(), + name: spec.name.clone(), python_version, unique_version, tag, @@ -202,10 +227,17 @@ pub fn install_all( .template("Installing {bar} {pos:>3}/{len:3} {wide_msg}") .unwrap(), // We know the template, it's correct ); - let current: Arc>> = Arc::new(Mutex::new(Vec::new())); + let current: Arc>> = Arc::new(Mutex::new(Vec::new())); let install_closure = |spec: &RequestedSpec| { current.lock().unwrap().push(spec.name.clone()); - pb.set_message(current.lock().unwrap().join(",")); + pb.set_message( + current + .lock() + .unwrap() + .iter() + .map(ToString::to_string) + .join(","), + ); if pb.is_hidden() { if let Some(source) = &spec.source { info!( @@ -234,12 +266,12 @@ pub fn install_all( { let mut current = current.lock().unwrap(); current.retain(|x| x != &spec.name); - pb.set_message(current.join(", ")); + pb.set_message(current.iter().map(ToString::to_string).join(",")); pb.inc(1); } let installed_package = InstalledPackage { - name: spec.normalized_name(), + name: spec.name.clone(), python_version, unique_version, tag, @@ -385,10 +417,10 @@ fn download_and_install( } FileOrUrl::Git { url, revision } => { let temp_dir = TempDir::new()?; - let repo_dir = temp_dir.path().join(&spec.name); + let repo_dir = temp_dir.path().join(spec.name.to_string()); repo_at_revision(&url, &revision, &repo_dir)?; - // If we got an sdist until now, build it into a wheel + // If we got a source dist until now, build it into a wheel debug!( "Building {} {} from source distribution to wheel", spec.name, spec.unique_version diff --git a/crates/monotrail/src/lib.rs b/crates/monotrail/src/lib.rs index d3b15fe..0e69644 100644 --- a/crates/monotrail/src/lib.rs +++ b/crates/monotrail/src/lib.rs @@ -30,7 +30,7 @@ mod monotrail; mod package_index; mod poetry_integration; mod ppipx; -#[cfg(feature = "python_bindings")] +#[cfg(feature = "pyo3")] mod python_bindings; mod source_distribution; mod spec; diff --git a/crates/monotrail/src/markers.rs b/crates/monotrail/src/markers.rs index 02501a9..6c6191f 100644 --- a/crates/monotrail/src/markers.rs +++ b/crates/monotrail/src/markers.rs @@ -6,7 +6,7 @@ use std::process::{Command, Stdio}; /// If we launch from python, we can call the python code from python with no overhead, but /// still need to parse into Self here -#[cfg_attr(not(feature = "python_bindings"), allow(dead_code))] +#[cfg_attr(not(feature = "pyo3"), allow(dead_code))] pub fn marker_environment_from_json_str(pep508_env_data: &str) -> MarkerEnvironment { serde_json::from_str(pep508_env_data).unwrap() } diff --git a/crates/monotrail/src/monotrail.rs b/crates/monotrail/src/monotrail.rs index 5ce7d4d..9c860b9 100644 --- a/crates/monotrail/src/monotrail.rs +++ b/crates/monotrail/src/monotrail.rs @@ -16,7 +16,7 @@ use fs_err::{DirEntry, File}; use install_wheel_rs::{CompatibleTags, InstallLocation, Script, SHEBANG_PYTHON}; use monotrail_utils::parse_cpython_args::determine_python_version; use monotrail_utils::standalone_python::provision_python; -use pep508_rs::MarkerEnvironment; +use pep508_rs::{ExtraName, MarkerEnvironment, PackageName}; use serde::Serialize; use std::collections::{BTreeMap, HashMap}; use std::env::{current_dir, current_exe}; @@ -25,6 +25,7 @@ use std::ffi::CString; use std::io::Read; use std::path::{Path, PathBuf}; use std::process::Command; +use std::str::FromStr; use std::{env, io}; use tempfile::TempDir; use tracing::{debug, info, trace, warn}; @@ -60,7 +61,7 @@ pub type SpecPaths = BTreeMap, Vec)>; /// The [FinderData] is made by the installation system, the other fields are made by the inject /// system -#[cfg_attr(feature = "python_bindings", pyo3::pyclass(dict, get_all))] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(dict, get_all))] #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct InjectData { /// The location of packages and imports @@ -76,7 +77,7 @@ pub struct InjectData { /// The packaging and import data that is resolved by the rust part and deployed by the finder /// /// Keep in sync with its python counterparts in convert_finder_data.py and monotrail.pyi -#[cfg_attr(feature = "python_bindings", pyo3::pyclass(dict, get_all))] +#[cfg_attr(feature = "pyo3", pyo3::pyclass(dict, get_all))] #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FinderData { /// The location where all packages are installed @@ -97,10 +98,10 @@ pub struct FinderData { pub root_scripts: BTreeMap, } -#[cfg_attr(feature = "python_bindings", pyo3::pymethods)] +#[cfg_attr(feature = "pyo3", pyo3::pymethods)] impl FinderData { /// For debugging - #[cfg_attr(not(feature = "python_bindings"), allow(dead_code))] + #[cfg_attr(not(feature = "pyo3"), allow(dead_code))] fn to_json(&self) -> String { serde_json::to_string(&self).expect("Couldn't convert to json") } @@ -139,7 +140,7 @@ fn find_dep_file(dir_running: &Path) -> Option<(PathBuf, LockfileType)> { pub fn list_installed( root: &Path, compatible_tags: Option<&CompatibleTags>, -) -> anyhow::Result> { +) -> anyhow::Result> { // Behold my monstrous iterator // name -> version -> compatible tag let mut compatible = Vec::new(); @@ -173,7 +174,8 @@ pub fn list_installed( continue; } compatible.push(( - name_dir.file_name().to_string_lossy().to_string(), + PackageName::from_str(name_dir.file_name().to_string_lossy().as_ref()) + .expect("TODO(konsti)"), version_dir.file_name().to_string_lossy().to_string(), tag, )) @@ -203,7 +205,7 @@ pub fn filter_installed_monotrail( if let Some(unique_version) = unique_version { if let Some((name, installed_version, tag)) = compatible.iter().find(|(name, installed_version, _tag)| { - name == &spec.normalized_name() && installed_version == &unique_version + name == &spec.name && installed_version == &unique_version }) { installed.push(InstalledPackage { @@ -223,7 +225,7 @@ pub fn filter_installed_monotrail( // This would take proper version resolution to make sense if let Some((name, unique_version, _path)) = compatible .iter() - .find(|(name, _version, _path)| name == &spec.normalized_name()) + .find(|(name, _version, _path)| name == &spec.name) { installed.push(InstalledPackage { // already normalized @@ -246,7 +248,7 @@ pub fn filter_installed_monotrail( /// script can be a manually set working directory or the python script we're running. /// Returns a list name, python version, unique version -#[cfg_attr(not(feature = "python_bindings"), allow(dead_code))] +#[cfg_attr(not(feature = "pyo3"), allow(dead_code))] pub fn install_missing( specs: &[RequestedSpec], python: &Path, @@ -318,7 +320,7 @@ pub fn install_missing( /// /// Returns the name, the main file to import for the spec and the submodule_search_locations /// as well as a list of .pth files that need to be executed -#[cfg_attr(not(feature = "python_bindings"), allow(dead_code))] +#[cfg_attr(not(feature = "pyo3"), allow(dead_code))] pub fn spec_paths( sprawl_root: &Path, sprawl_packages: &[InstalledPackage], @@ -434,7 +436,7 @@ pub fn spec_paths( #[allow(clippy::type_complexity)] pub fn load_specs( script: Option<&Path>, - extras: &[String], + extras: &[ExtraName], python_context: &PythonContext, ) -> anyhow::Result<( Vec, @@ -532,7 +534,7 @@ pub fn load_specs( /// lockfile pub fn specs_from_requirements_txt_resolved( requirements_txt: &Path, - extras: &[String], + extras: &[ExtraName], lockfile: Option<&str>, python_context: &PythonContext, ) -> anyhow::Result<(Vec, String)> { @@ -577,7 +579,10 @@ pub fn install( // If you want to help this project please make a pull request to jupyter to also make it search // relative to the package, based on ipykernel.__file__ or ipykernel.__path__ :) // https://docs.jupyter.org/en/latest/use/jupyter-directories.html#data-files - if let Some(jupyter) = sprawl_packages.iter().find(|x| x.name == "ipykernel") { + if let Some(jupyter) = sprawl_packages + .iter() + .find(|x| x.name == PackageName::from_str("ipykernel").unwrap()) + { let mut jupyter_path = jupyter .monotrail_location(PathBuf::from(&sprawl_root)) .join("share") @@ -666,7 +671,7 @@ pub fn is_python_script(executable: &Path) -> anyhow::Result { /// Run an installed command pub fn run_command( - extras: &[String], + extras: &[ExtraName], python_version: Option<&str>, root: Option<&Path>, command: &str, @@ -803,7 +808,7 @@ pub fn run_command_finder_data( pub fn cli_from_git( git_url: &str, revision: &str, - extras: &[String], + extras: &[ExtraName], python_version: Option, args: &[String], ) -> anyhow::Result> { diff --git a/crates/monotrail/src/package_index.rs b/crates/monotrail/src/package_index.rs index 235b941..3d89c6c 100644 --- a/crates/monotrail/src/package_index.rs +++ b/crates/monotrail/src/package_index.rs @@ -4,6 +4,7 @@ use crate::spec::DistributionType; use anyhow::{bail, Context, Result}; use fs_err as fs; use install_wheel_rs::{CompatibleTags, Error, WheelFilename}; +use pep508_rs::PackageName; use serde::Deserialize; use std::collections::HashMap; use std::io; @@ -91,7 +92,7 @@ fn matching_package_for_version( /// pub fn search_release( host: &str, - name: &str, + name: &PackageName, version: Option, compatible_tags: &CompatibleTags, ) -> Result<(PypiRelease, DistributionType, String)> { diff --git a/crates/monotrail/src/poetry_integration/lock.rs b/crates/monotrail/src/poetry_integration/lock.rs index 51c9f83..9763e23 100644 --- a/crates/monotrail/src/poetry_integration/lock.rs +++ b/crates/monotrail/src/poetry_integration/lock.rs @@ -9,9 +9,11 @@ use crate::read_poetry_specs; use crate::utils::cache_dir; use anyhow::{bail, format_err, Context}; use fs_err as fs; +use pep508_rs::PackageName; use std::collections::BTreeMap; use std::default::Default; use std::process::Command; +use std::str::FromStr; use std::time::Instant; use std::{env, io}; use tempfile::{tempdir, TempDir}; @@ -19,13 +21,13 @@ use tracing::{debug, span, Level}; /// Minimal dummy pyproject.toml with the user requested deps for poetry to resolve pub fn dummy_poetry_pyproject_toml( - dependencies: &BTreeMap, + dependencies: &BTreeMap, python_version: (u8, u8), ) -> PoetryPyprojectToml { let mut dependencies = dependencies.clone(); // Add python entry with current version; resolving will otherwise fail with complaints dependencies.insert( - "python".to_string(), + PackageName::from_str("python").unwrap(), // For some reason on github actions 3.8.12 is not 3.8 compatible, so we name the range explicitly poetry_toml::Dependency::Compact(format!( ">={}.{},<{}.{}", @@ -55,7 +57,7 @@ pub fn dummy_poetry_pyproject_toml( /// Calls poetry to resolve the user specified dependencies into a set of locked consistent /// dependencies. Produces a poetry.lock in the process pub fn poetry_resolve( - dependencies: &BTreeMap, + dependencies: &BTreeMap, lockfile: Option<&str>, python_context: &PythonContext, ) -> anyhow::Result<(PoetrySection, PoetryLock, String)> { diff --git a/crates/monotrail/src/poetry_integration/poetry_lock.rs b/crates/monotrail/src/poetry_integration/poetry_lock.rs index 0555256..737b21d 100644 --- a/crates/monotrail/src/poetry_integration/poetry_lock.rs +++ b/crates/monotrail/src/poetry_integration/poetry_lock.rs @@ -1,7 +1,7 @@ //! Types for poetry.lock use anyhow::bail; -use pep508_rs::{MarkerEnvironment, MarkerTree}; +use pep508_rs::{ExtraName, MarkerEnvironment, MarkerTree, PackageName}; use regex::Regex; use serde::Deserialize; use std::collections::{HashMap, HashSet}; @@ -32,11 +32,11 @@ impl PoetryLock { /// its on each package. /// /// Pass the package name already normalized - pub fn get_filenames(&self, package_name: &str) -> Option<&Vec> { + pub fn get_filenames(&self, package_name: &PackageName) -> Option<&Vec> { if let Some(v1_1) = &self.metadata.files { return v1_1.get(package_name); } - if let Some(v2_0) = self.package.iter().find(|p| p.name == package_name) { + if let Some(v2_0) = self.package.iter().find(|p| &p.name == package_name) { return v2_0.files.as_ref(); } // outdated lockfile, to be handled downstream @@ -49,7 +49,7 @@ impl PoetryLock { #[serde(rename_all = "kebab-case")] #[allow(dead_code)] pub struct Package { - pub name: String, + pub name: PackageName, pub version: String, pub description: String, pub category: Option, @@ -59,7 +59,7 @@ pub struct Package { pub extras: HashMap>, // https://github.com/alexcrichton/toml-rs/issues/142#issuecomment-279009115 #[serde(serialize_with = "toml::ser::tables_last")] - pub dependencies: Option>, + pub dependencies: Option>, pub source: Option, // Only in lock file format 2.0/poetry 1.3 or newer pub files: Option>, @@ -71,7 +71,7 @@ pub struct Package { pub struct DependencyExpanded { pub version: String, pub markers: Option, - pub extras: Option>, + pub extras: Option>, } /// `[package.dependencies]` @@ -96,17 +96,17 @@ pub enum Dependency { } impl Dependency { - /// checks if we need to install given the markers and returns the matching version constraint + /// Checks if we need to install given the markers and returns the matching version constraint /// /// For the extras we give in a set of extras the is activated for self to check if we need /// self->dep, and return the extras active for self->dep pub fn get_version_and_extras( &self, environment: &MarkerEnvironment, - self_extras: &HashSet, - ) -> Result)>, String> { + self_extras: &HashSet, + ) -> Result)>, String> { let extra_re = Regex::new(r#"^extra == "([\w\d_-]+)"$"#).unwrap(); - let self_extras_vec: Vec<&str> = self_extras.iter().map(|str| str.as_str()).collect(); + let self_extras_vec: Vec = self_extras.iter().cloned().collect(); Ok(match self { Dependency::Compact(version) => Some((version.to_string(), Vec::new())), @@ -117,7 +117,9 @@ impl Dependency { }) => { if let Some(markers) = markers { if let Some(captures) = extra_re.captures(markers) { - if self_extras.contains(&captures[1].to_string()) { + if self_extras.contains( + &ExtraName::from_str(&captures[1]).map_err(|err| err.to_string())?, + ) { Some((version.to_string(), extras.clone().unwrap_or_default())) } else { None @@ -138,7 +140,10 @@ impl Dependency { for option in options { if let Some(markers) = &option.markers { if let Some(captures) = extra_re.captures(markers) { - if self_extras.contains(&captures[1].to_string()) { + if self_extras.contains( + &ExtraName::from_str(&captures[1]) + .map_err(|err| err.to_string())?, + ) { return Ok(Some(( option.version.to_string(), option.extras.clone().unwrap_or_default(), @@ -190,7 +195,7 @@ pub struct Metadata { pub content_hash: String, /// `[metadata.files]` /// Only in lock_version 1.1, in version 2.0/poetry 1.3 it's in each package - pub files: Option>>, + pub files: Option>>, } /// e.g. `{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}` @@ -205,14 +210,16 @@ pub struct HashedFile { #[cfg(test)] mod test { use crate::poetry_integration::poetry_lock::PoetryLock; + use pep508_rs::PackageName; use std::fs; use std::path::Path; + use std::str::FromStr; fn get_filenames(filename: &str, package: &str) -> usize { let filename = Path::new("../../test-data").join(filename); PoetryLock::from_str(&fs::read_to_string(filename).unwrap()) .unwrap() - .get_filenames(package) + .get_filenames(&PackageName::from_str(package).unwrap()) .unwrap() .len() } diff --git a/crates/monotrail/src/poetry_integration/poetry_toml.rs b/crates/monotrail/src/poetry_integration/poetry_toml.rs index c0c6008..b19f9a7 100644 --- a/crates/monotrail/src/poetry_integration/poetry_toml.rs +++ b/crates/monotrail/src/poetry_integration/poetry_toml.rs @@ -1,5 +1,6 @@ //! Types for poetry.toml +use pep508_rs::{ExtraName, PackageName}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -57,7 +58,7 @@ pub enum Dependency { Expanded { version: Option, optional: Option, - extras: Option>, + extras: Option>, git: Option, branch: Option, }, @@ -71,7 +72,7 @@ impl Dependency { } } - pub fn get_extras(&self) -> &[String] { + pub fn get_extras(&self) -> &[ExtraName] { match self { Dependency::Compact(_) => &[], Dependency::Expanded { extras, .. } => extras.as_deref().unwrap_or_default(), @@ -94,8 +95,8 @@ pub struct PoetrySection { pub version: String, pub description: String, pub authors: Vec, - pub dependencies: BTreeMap, - pub dev_dependencies: Option>, - pub extras: Option>>, + pub dependencies: BTreeMap, + pub dev_dependencies: Option>, + pub extras: Option>>, pub scripts: Option>, } diff --git a/crates/monotrail/src/poetry_integration/read_dependencies.rs b/crates/monotrail/src/poetry_integration/read_dependencies.rs index 3ef1ae2..b8e34d2 100644 --- a/crates/monotrail/src/poetry_integration/read_dependencies.rs +++ b/crates/monotrail/src/poetry_integration/read_dependencies.rs @@ -10,9 +10,9 @@ use crate::spec::{DistributionType, RequestedSpec, SpecSource}; use crate::utils::cache_dir; use anyhow::{bail, Context}; use fs_err as fs; -use install_wheel_rs::{normalize_name, CompatibleTags, Error, Script, WheelFilename}; +use install_wheel_rs::{CompatibleTags, Error, Script, WheelFilename}; use monotrail_utils::RequirementsTxt; -use pep508_rs::{MarkerEnvironment, VersionOrUrl}; +use pep508_rs::{ExtraName, MarkerEnvironment, PackageName, VersionOrUrl}; use regex::Regex; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; @@ -69,7 +69,7 @@ pub fn filename_and_url( let url = format!( "https://files.pythonhosted.org/packages/{}/{}/{}/{}", parsed.python_tag.join("."), - package.name.chars().next().unwrap(), + package.name.to_string().chars().next().unwrap(), package.name, filename, ); @@ -84,7 +84,7 @@ pub fn filename_and_url( let url = format!( "https://files.pythonhosted.org/packages/{}/{}/{}/{}", "source", - package.name.chars().next().unwrap(), + package.name.to_string().chars().next().unwrap(), package.name, hashed_file.file, ); @@ -120,7 +120,6 @@ fn parse_dep_extra(dep_spec: &str) -> Result<(String, HashSet, Option Result<(String, HashSet, Option, - deps_with_extras: BTreeMap>, + packages: HashMap, + deps_with_extras: BTreeMap>, ) -> anyhow::Result> { let mut specs = Vec::new(); for (dep_name, dep_extras) in deps_with_extras { - let norm_name = normalize_name(&dep_name); - let package = if let Some(package) = packages.get(&norm_name) { + let package = if let Some(package) = packages.get(&dep_name) { package - } else if UNSAFE_DEPS.contains(&dep_name.as_str()) { + } else if UNSAFE_DEPS.contains(&dep_name.to_string().as_str()) { continue; } else { debug!("Packages: {:?}", packages.keys().collect::>()); bail!( "Lockfile outdated (run `poetry update`): {} is missing", - norm_name + dep_name ) }; let spec = RequestedSpec { @@ -174,8 +172,8 @@ fn resolution_to_specs( fn get_root_info( poetry_section: &PoetrySection, no_dev: bool, - extras: &[String], -) -> anyhow::Result> { + extras: &[ExtraName], +) -> anyhow::Result> { let root_deps = if no_dev { poetry_section.dependencies.clone() } else { @@ -187,7 +185,7 @@ fn get_root_info( .collect() }; - let mut root_extra_deps: HashSet = HashSet::new(); + let mut root_extra_deps: HashSet = HashSet::new(); for extra_name in extras { let packages = poetry_section .extras @@ -201,7 +199,7 @@ fn get_root_info( .into_iter() .filter(|(dep_name, dep_spec)| { // We do not need to install python (oh if we only could, relocatable python a dream) - if dep_name == "python" { + if dep_name.to_string() == "python" { return false; } // Use only those optional deps which are activated by a selected extra @@ -217,15 +215,14 @@ fn get_root_info( fn get_packages_from_lockfile( poetry_lock: &PoetryLock, -) -> anyhow::Result> { +) -> anyhow::Result> { // keys are normalized names since `[package.dependencies]` also uses normalized names - let packages: HashMap = poetry_lock + Ok(poetry_lock .package .clone() .into_iter() - .map(|package| (normalize_name(&package.name), package)) - .collect(); - Ok(packages) + .map(|package| (package.name.clone(), package)) + .collect()) } /// Reads pyproject.toml and poetry.lock, also returns poetry.lock as string @@ -247,7 +244,7 @@ pub fn read_poetry_specs( poetry_section: &PoetrySection, poetry_lock: PoetryLock, no_dev: bool, - extras: &[String], + extras: &[ExtraName], pep508_env: &MarkerEnvironment, ) -> anyhow::Result> { // The deps in pyproject.toml which we need to read explicitly since they aren't marked @@ -258,19 +255,17 @@ pub fn read_poetry_specs( // This is the thing we want to build: a list with all transitive dependencies and // all their (transitively activated) features - let mut deps_with_extras: BTreeMap> = BTreeMap::new(); + let mut deps_with_extras: BTreeMap> = BTreeMap::new(); // (dep, dep->extra) combinations we still need to process - let mut queue: VecDeque<(String, HashSet)> = VecDeque::new(); + let mut queue: VecDeque<(PackageName, HashSet)> = VecDeque::new(); // Since we have no explicit root package, prime manually for (dep_name, dep_spec) in root_deps { - let dep_name_norm = normalize_name(&dep_name.to_lowercase()); - queue.push_back(( - dep_name_norm.clone(), + dep_name.clone(), dep_spec.get_extras().iter().cloned().collect(), )); deps_with_extras.insert( - dep_name_norm.clone(), + dep_name.clone(), dep_spec.get_extras().iter().cloned().collect(), ); } @@ -278,24 +273,22 @@ pub fn read_poetry_specs( // resolve the dependencies-extras tree // (dep, dep->extra) while let Some((dep_name, self_extras)) = queue.pop_front() { - let norm_name = normalize_name(&dep_name); let package = if let Some(package) = packages // search by normalized name - .get(&norm_name) + .get(&dep_name) { package - } else if UNSAFE_DEPS.contains(&dep_name.as_str()) { + } else if UNSAFE_DEPS.contains(&dep_name.to_string().as_str()) { continue; } else { debug!("Packages: {:?}", packages.keys().collect::>()); bail!( "Lockfile outdated (run `poetry update`): {} is missing", - norm_name + dep_name ) }; // descend one level into the dep tree for (new_dep_name, new_dep) in package.dependencies.clone().unwrap_or_default() { - let new_dep_name_norm = new_dep_name.to_lowercase().replace('-', "_"); // Check the extras selected on the current dep activate the transitive dependency let (_new_dep_version, new_dep_extras) = match new_dep .get_version_and_extras(pep508_env, &self_extras) @@ -305,7 +298,7 @@ pub fn read_poetry_specs( Some((version, new_dep_extras)) => (version, new_dep_extras), }; - let new_dep_extras: HashSet = new_dep_extras.into_iter().collect(); + let new_dep_extras: HashSet = new_dep_extras.into_iter().collect(); let new_extras = if let Some(known_extras) = deps_with_extras.get(&new_dep_name) { if new_dep_extras.is_subset(known_extras) { @@ -319,10 +312,10 @@ pub fn read_poetry_specs( }; deps_with_extras - .entry(new_dep_name_norm.clone()) + .entry(new_dep_name.clone()) .or_default() .extend(new_extras.clone()); - queue.push_back((new_dep_name_norm.clone(), new_extras)); + queue.push_back((new_dep_name.clone(), new_extras)); } } @@ -330,11 +323,11 @@ pub fn read_poetry_specs( } /// Checkouts the specified revision to the cache dir, if not present -#[cfg_attr(not(feature = "python_bindings"), allow(dead_code))] +#[cfg_attr(not(feature = "pyo3"), allow(dead_code))] pub fn specs_from_git( url: &str, revision: &str, - extras: &[String], + extras: &[ExtraName], lockfile: Option<&str>, python_context: &PythonContext, ) -> anyhow::Result<(Vec, PathBuf, String)> { @@ -411,7 +404,7 @@ pub fn specs_from_git( /// the lockfile string pub fn poetry_spec_from_dir( dep_file_location: &Path, - extras: &[String], + extras: &[ExtraName], pep508_env: &MarkerEnvironment, ) -> anyhow::Result<(Vec, BTreeMap, String)> { let (poetry_section, poetry_lock, lockfile) = read_toml_files(dep_file_location)?; @@ -431,7 +424,7 @@ pub fn poetry_spec_from_dir( pub fn read_requirements_for_poetry( requirements_txt: &Path, working_dir: &Path, -) -> anyhow::Result> { +) -> anyhow::Result> { let data = RequirementsTxt::parse(requirements_txt, working_dir)?; if !data.constraints.is_empty() { bail!( @@ -439,7 +432,7 @@ pub fn read_requirements_for_poetry( requirements_txt.display() ); } - let mut poetry_requirements: BTreeMap = BTreeMap::new(); + let mut poetry_requirements: BTreeMap = BTreeMap::new(); for requirement_entry in data.requirements { let version = match requirement_entry.requirement.version_or_url { None => "*".to_string(), @@ -456,7 +449,7 @@ pub fn read_requirements_for_poetry( let dep = poetry_toml::Dependency::Expanded { version: Some(version), optional: Some(false), - extras: requirement_entry.requirement.extras.clone(), + extras: Some(requirement_entry.requirement.extras.clone()), git: None, branch: None, }; @@ -472,7 +465,7 @@ mod test { }; use crate::read_poetry_specs; use indoc::indoc; - use pep508_rs::{MarkerEnvironment, StringVersion}; + use pep508_rs::{ExtraName, MarkerEnvironment, StringVersion}; use std::collections::HashSet; use std::path::Path; use std::str::FromStr; @@ -528,12 +521,32 @@ mod test { let expected = [ (mst, true, vec![], 95), (mst, false, vec![], 130), - (mst, true, vec!["import-json".to_string()], 97), - (mst, false, vec!["import-json".to_string()], 131), + ( + mst, + true, + vec![ExtraName::from_str("import-json").unwrap()], + 97, + ), + ( + mst, + false, + vec![ExtraName::from_str("import-json").unwrap()], + 131, + ), (data_science, true, vec![], 15), (data_science, false, vec![], 21), - (data_science, true, vec!["tqdm_feature".to_string()], 16), - (data_science, false, vec!["tqdm_feature".to_string()], 22), + ( + data_science, + true, + vec![ExtraName::from_str("tqdm_feature").unwrap()], + 16, + ), + ( + data_science, + false, + vec![ExtraName::from_str("tqdm_feature").unwrap()], + 22, + ), ]; for (toml_dir, no_dev, extras, specs_count) in expected { @@ -556,10 +569,12 @@ mod test { [inflection] version = "==0.5.1" optional = false + extras = [] [numpy] version = "*" optional = false + extras = [] [pandas] version = ">=1, <2" @@ -569,6 +584,7 @@ mod test { [upsidedown] version = "==0.4" optional = false + extras = [] "#}; let working_dir = Path::new("../../test-data").join("requirements-txt"); diff --git a/crates/monotrail/src/poetry_integration/run.rs b/crates/monotrail/src/poetry_integration/run.rs index 5f97be8..49a5804 100644 --- a/crates/monotrail/src/poetry_integration/run.rs +++ b/crates/monotrail/src/poetry_integration/run.rs @@ -8,8 +8,10 @@ use crate::poetry_integration::poetry_toml::PoetryPyprojectToml; use crate::{read_poetry_specs, DEFAULT_PYTHON_VERSION}; use anyhow::Context; use monotrail_utils::parse_cpython_args::determine_python_version; +use pep508_rs::PackageName; use std::collections::BTreeMap; use std::path::PathBuf; +use std::str::FromStr; /// Use the libpython.so to run a poetry command on python 3.8, unless you give +x.y as first /// argument @@ -44,7 +46,7 @@ pub fn poetry_run(args: &[String], python_version: Option<&str>) -> anyhow::Resu let poetry_package = finder_data .sprawl_packages .iter() - .find(|package| package.name == "poetry") + .find(|package| package.name == PackageName::from_str("poetry").unwrap()) .context("poetry is missing 🤨")?; let base = poetry_package.monotrail_location(PathBuf::from(&finder_data.sprawl_root)); let launcher = if cfg!(windows) { diff --git a/crates/monotrail/src/ppipx.rs b/crates/monotrail/src/ppipx.rs index 0b860aa..8465dc1 100644 --- a/crates/monotrail/src/ppipx.rs +++ b/crates/monotrail/src/ppipx.rs @@ -8,9 +8,12 @@ use crate::utils::data_local_dir; use crate::{read_poetry_specs, DEFAULT_PYTHON_VERSION}; use anyhow::Context; use fs_err as fs; +use itertools::Itertools; use monotrail_utils::parse_cpython_args::parse_major_minor; +use pep508_rs::{ExtraName, PackageName}; use std::collections::BTreeMap; use std::path::PathBuf; +use std::str::FromStr; use tempfile::TempDir; use tracing::{debug, info}; @@ -18,10 +21,10 @@ use tracing::{debug, info}; /// /// Resolves one package, saving it in .local and runs one command from it pub fn ppipx( - package: Option<&str>, + package: Option<&PackageName>, python_version: Option<&str>, version: Option<&str>, - extras: &[String], + extras: &[ExtraName], command: &str, args: &[String], ) -> anyhow::Result { @@ -31,11 +34,19 @@ pub fn ppipx( .unwrap_or(DEFAULT_PYTHON_VERSION); let (python_context, python_home) = provision_python_env(python_version)?; - let package = package.unwrap_or(command); + let package = if let Some(package) = package { + package.clone() + } else { + PackageName::from_str(command).context("Command name is not a valid package name")? + }; let package_extras = if extras.is_empty() { package.to_string() } else { - format!("{}[{}]", package, extras.join(",")) + format!( + "{}[{}]", + package, + extras.iter().map(ToString::to_string).join(",") + ) }; let resolution_dir = data_local_dir()? @@ -54,7 +65,7 @@ pub fn ppipx( extras, python_version, &python_context, - package, + &package, &resolution_dir, )?; } else { @@ -80,16 +91,16 @@ pub fn ppipx( /// Writes a pyproject.toml for the ppipx command and calls poetry to resolve it to a poetry.lock fn generate_ppipx_entry( version: Option<&str>, - extras: &[String], + extras: &[ExtraName], python_version: (u8, u8), python_context: &PythonContext, - package: &str, + package: &PackageName, resolution_dir: &PathBuf, ) -> anyhow::Result<()> { let mut dependencies = BTreeMap::new(); // Add python entry with current version; resolving will otherwise fail with complaints dependencies.insert( - "python".to_string(), + PackageName::from_str("python")?, // For some reason on github actions 3.8.12 is not 3.8 compatible, so we name the range explicitly poetry_toml::Dependency::Compact(format!( ">={}.{},<{}.{}", @@ -101,12 +112,12 @@ fn generate_ppipx_entry( ); if extras.is_empty() { dependencies.insert( - package.to_string(), + package.clone(), poetry_toml::Dependency::Compact(version.unwrap_or("*").to_string()), ); } else { dependencies.insert( - package.to_string(), + package.clone(), poetry_toml::Dependency::Expanded { version: Some(version.unwrap_or("*").to_string()), optional: None, diff --git a/crates/monotrail/src/python_bindings.rs b/crates/monotrail/src/python_bindings.rs index ed6613a..da9fc4d 100644 --- a/crates/monotrail/src/python_bindings.rs +++ b/crates/monotrail/src/python_bindings.rs @@ -14,15 +14,18 @@ use crate::monotrail::{ use crate::poetry_integration::lock::poetry_resolve; use crate::poetry_integration::read_dependencies::specs_from_git; use crate::{read_poetry_specs, PEP508_QUERY_ENV}; -use anyhow::{bail, Context}; +use anyhow::Context; use install_wheel_rs::Script; use monotrail_utils::parse_cpython_args::naive_python_arg_parser; +use pep508_rs::ExtraName; use pyo3::exceptions::PyRuntimeError; +use pyo3::prelude::PyAnyMethods; use pyo3::types::PyModule; -use pyo3::{pyfunction, pymodule, wrap_pyfunction, Py, PyAny, PyErr, PyResult, Python}; +use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, Py, PyAny, PyErr, PyResult, Python}; use std::collections::BTreeMap; use std::env; use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::sync::Once; use tracing::{debug, trace}; @@ -52,7 +55,7 @@ fn injectable( /// Uses the python C API to run a code snippet that json encodes the PEP508 env fn get_pep508_env(py: Python) -> PyResult { let fun: Py = - PyModule::from_code(py, PEP508_QUERY_ENV, "get_pep508_env.py", "get_pep508_env")? + PyModule::from_code_bound(py, PEP508_QUERY_ENV, "get_pep508_env.py", "get_pep508_env")? .getattr("get_pep508_env")? .into(); @@ -75,7 +78,7 @@ fn get_python_context(py: Python) -> PyResult { }); } // Would be nicer through https://docs.python.org/3/c-api/init.html#c.Py_GetProgramFullPath - let sys_executable: String = py.import("sys")?.getattr("executable")?.extract()?; + let sys_executable: String = py.import_bound("sys")?.getattr("executable")?.extract()?; let python_context = PythonContext { sys_executable: PathBuf::from(sys_executable), version: (py.version_info().major, py.version_info().minor), @@ -154,6 +157,16 @@ pub fn monotrail_from_git( let python_context = get_python_context(py)?; debug!("extras: {:?}", extras); + let extras: Option> = extras + .map(|extras| { + extras + .iter() + .map(|extra| ExtraName::from_str(extra)) + .collect() + }) + .transpose() + .map_err(format_monotrail_error)?; + let (specs, repo_dir, lockfile) = specs_from_git( &git_url, &revision, @@ -181,6 +194,12 @@ pub fn monotrail_from_dir(py: Python, dir: PathBuf, extras: Vec) -> PyRe let python_context = get_python_context(py)?; debug!("extras: {:?}", extras); + let extras = extras + .iter() + .map(|extra| ExtraName::from_str(extra)) + .collect::, _>>() + .map_err(format_monotrail_error)?; + let (specs, scripts, lockfile, project_dir) = load_specs(Some(&dir), &extras, &python_context).map_err(format_monotrail_error)?; let finder_data = install( @@ -221,26 +240,16 @@ pub fn monotrail_find_scripts( find_scripts(&sprawl_packages, &sprawl_root).map_err(format_monotrail_error) } -fn parse_extras() -> anyhow::Result> { +fn parse_extras() -> anyhow::Result> { let extras_env_var = format!("{}_EXTRAS", env!("CARGO_PKG_NAME").to_uppercase()); let extras = if let Some(extras) = env::var_os(&extras_env_var) { - let extras: Vec = extras + extras .into_string() .ok() // can't use the original OsString .with_context(|| format!("{} must only contain utf-8 characters", extras_env_var))? .split(',') - .map(ToString::to_string) - .collect(); - for extra in &extras { - let allowed = |x: char| x.is_alphanumeric() || x == '-' || x == '_'; - if !extra.chars().all(allowed) { - bail!( - "Invalid extra name '{}', allowed are underscore, minus, letters and digits", - extra - ); - } - } - extras + .map(ExtraName::from_str) + .collect::, _>>()? } else { Vec::new() }; @@ -248,7 +257,7 @@ fn parse_extras() -> anyhow::Result> { } #[pymodule] -pub fn monotrail(_py: Python, m: &PyModule) -> PyResult<()> { +pub fn monotrail(_py: Python, m: &Bound) -> PyResult<()> { // Good enough for now if env::var_os("RUST_LOG").is_some() { tracing_subscriber::fmt::init(); diff --git a/crates/monotrail/src/source_distribution.rs b/crates/monotrail/src/source_distribution.rs index 1e1cef6..790bdb1 100644 --- a/crates/monotrail/src/source_distribution.rs +++ b/crates/monotrail/src/source_distribution.rs @@ -4,6 +4,7 @@ use crate::utils::cache_dir; use anyhow::{bail, Context, Result}; use fs_err as fs; use install_wheel_rs::{CompatibleTags, Error, WheelFilename}; +use pep508_rs::PackageName; use std::ffi::OsString; use std::io; use std::path::{Path, PathBuf}; @@ -14,12 +15,15 @@ use tempfile::TempDir; /// Takes a source distribution, checks whether we have already built a matching wheel, and if /// not, builds a wheels from the source distribution by invoking `pip wheel --no-deps` pub fn build_source_distribution_to_wheel_cached( - name: &str, + name: &PackageName, version: &str, sdist: &Path, compatible_tags: &CompatibleTags, ) -> Result { - let target_dir = cache_dir()?.join("artifacts").join(name).join(version); + let target_dir = cache_dir()? + .join("artifacts") + .join(name.to_string()) + .join(version); if let Ok(target_dir) = fs::read_dir(&target_dir) { for entry in target_dir.flatten() { @@ -43,7 +47,7 @@ pub fn build_source_distribution_to_wheel_cached( Ok(wheel_in_cache) } -/// Builds a wheel from an source distribution or a repo checkout using `pip wheel --no-deps` +/// Builds a wheel from a source distribution or a repo checkout using `pip wheel --no-deps` pub fn build_to_wheel( sdist_or_dir: &Path, // needs to be passed in or the tempdir will be deleted to early diff --git a/crates/monotrail/src/spec.rs b/crates/monotrail/src/spec.rs index d6db97f..776655b 100644 --- a/crates/monotrail/src/spec.rs +++ b/crates/monotrail/src/spec.rs @@ -2,8 +2,8 @@ //! ([ResolvedSpec]). use crate::package_index::search_release; -use install_wheel_rs::{normalize_name, CompatibleTags, Error, WheelFilename}; -use regex::Regex; +use install_wheel_rs::{CompatibleTags, Error, WheelFilename}; +use pep508_rs::{ExtraName, PackageName}; use std::path::PathBuf; use std::str::FromStr; @@ -35,12 +35,12 @@ pub struct RequestedSpec { /// Will be printed with the error message to indicate what was tried to install pub requested: String, /// The name of the package - pub name: String, + pub name: PackageName, /// The version of the package pub python_version: Option, pub source: Option, /// The extras of the package to also be installed - pub extras: Vec, + pub extras: Vec, /// TODO: allow sdist filepath pub file_path: Option<(PathBuf, WheelFilename)>, /// Url, filename, distribution type @@ -48,10 +48,6 @@ pub struct RequestedSpec { } impl RequestedSpec { - pub fn normalized_name(&self) -> String { - normalize_name(&self.name) - } - pub fn get_unique_version(&self) -> Option { if let Some(source) = &self.source { Some(source.resolved_reference.clone()) @@ -61,7 +57,7 @@ impl RequestedSpec { } /// Parses "package_name", "package_name==version" and "some/path/tqdm-4.62.3-py2.py3-none-any.whl" - pub fn from_requested(requested: impl AsRef, extras: &[String]) -> Result { + pub fn from_requested(requested: impl AsRef, extras: &[ExtraName]) -> Result { if requested.as_ref().ends_with(".whl") { let file_path = PathBuf::from(requested.as_ref()); let filename = file_path @@ -79,22 +75,20 @@ impl RequestedSpec { url: None, }) } else { - // TODO: check actual naming rules - let valid_name = Regex::new(r"[-_a-zA-Z\d.]+").unwrap(); if let Some((name, version)) = requested.as_ref().split_once("==") { Ok(Self { requested: requested.as_ref().to_string(), - name: name.to_string(), + name: PackageName::from_str(name)?, python_version: Some(version.to_string()), source: None, extras: extras.to_vec(), file_path: None, url: None, }) - } else if valid_name.is_match(requested.as_ref()) { + } else if let Ok(name) = PackageName::from_str(requested.as_ref()) { Ok(Self { requested: requested.as_ref().to_string(), - name: requested.as_ref().to_string(), + name, python_version: None, source: None, extras: extras.to_vec(), @@ -187,7 +181,7 @@ pub enum FileOrUrl { #[derive(Debug, Clone, Eq, PartialEq)] pub struct ResolvedSpec { pub requested: String, - pub name: String, + pub name: PackageName, /// The pep440 version as importlib.metadata sees it pub python_version: String, /// A (hopefully) unique identifier for that package. This is the same as python_version @@ -196,7 +190,7 @@ pub struct ResolvedSpec { /// We serialize the version to a (hopefully) unique string /// TODO: Make sure it's actually unique and document how we do that pub unique_version: String, - pub extras: Vec, + pub extras: Vec, pub location: FileOrUrl, pub distribution_type: DistributionType, } @@ -209,9 +203,12 @@ mod test { use crate::utils::zstd_json_mock; use install_wheel_rs::{Arch, CompatibleTags, Os}; use mockito::Server; + use pep508_rs::PackageName; use std::path::Path; + use std::str::FromStr; fn manylinux_url(host: &str, package: &str) -> anyhow::Result { + let package = PackageName::from_str(package).unwrap(); let os = Os::Manylinux { major: 2, minor: 27, diff --git a/crates/monotrail/src/verify_installation.rs b/crates/monotrail/src/verify_installation.rs index c9d57e0..566ea61 100644 --- a/crates/monotrail/src/verify_installation.rs +++ b/crates/monotrail/src/verify_installation.rs @@ -8,6 +8,7 @@ use fs_err as fs; use fs_err::File; use indicatif::ProgressBar; use install_wheel_rs::{read_record_file, relative_to}; +use pep508_rs::PackageName; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use sha2::{Digest, Sha256}; use std::collections::HashMap; @@ -19,12 +20,12 @@ use walkdir::WalkDir; /// Checks a single package in `root` against its RECORD fn verify_package( root: &Path, - name: &str, + name: &PackageName, unique_version: &str, tag: &str, ) -> anyhow::Result> { let mut failing = Vec::new(); - let package_root = root.join(name).join(unique_version).join(tag); + let package_root = root.join(name.to_string()).join(unique_version).join(tag); let site_packages = if cfg!(windows) { package_root.join("Lib").join("site-packages") } else { @@ -46,7 +47,7 @@ fn verify_package( // normalize package name .to_lowercase() .replace('-', "_") - .starts_with(name) + .starts_with(&name.to_string()) && dir.file_name().to_string_lossy().ends_with(".dist-info") }) .map(|entry| entry.path()) diff --git a/pyproject.toml b/pyproject.toml index d583c16..eab594c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ monotrail_python = "monotrail.run_python:main" monotrail_script = "monotrail.run_script:main" [tool.maturin] -features = ["python_bindings"] +features = ["pyo3"] bindings = "pyo3" python-source = "python" diff --git a/python/monotrail/__init__.py b/python/monotrail/__init__.py index 3a0fe14..1681ebd 100644 --- a/python/monotrail/__init__.py +++ b/python/monotrail/__init__.py @@ -2,6 +2,7 @@ Loading this module will run monotrail, installing all required packages and making them loadable """ + import os import sys from typing import Optional, List diff --git a/python/monotrail/_monotrail_finder.py b/python/monotrail/_monotrail_finder.py index 4512ade..b8f777a 100644 --- a/python/monotrail/_monotrail_finder.py +++ b/python/monotrail/_monotrail_finder.py @@ -138,7 +138,10 @@ def _patch_pkg_resources(self, finder_data: "FinderData"): This functions patches pkg_resources so it can also find the distributions""" # Lazy import because i want to avoid triggering pkg_resources if not required - import pkg_resources + try: + import pkg_resources + except ModuleNotFoundError: + return for sprawl_package in finder_data.sprawl_packages: site_packages = sprawl_package.monotrail_site_packages( diff --git a/test/install_wheel_rs/test_popular.py b/test/install_wheel_rs/test_popular.py index 8cede5e..5e08a4d 100755 --- a/test/install_wheel_rs/test_popular.py +++ b/test/install_wheel_rs/test_popular.py @@ -2,6 +2,7 @@ """ Test with the top 100 pypi wheels and some more """ + from subprocess import check_call from test.install_wheel_rs.utils import get_root, compare_with_pip_wheels