From d8e96a42f8f341d6da7520f37e8b04eec7b727b2 Mon Sep 17 00:00:00 2001 From: Tarun Pratap Singh <101409098+Wackyator@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:49:18 +0530 Subject: [PATCH] feat: add PathsJson (#568) --- py-rattler/Cargo.lock | 278 ++++++------- py-rattler/docs/file_mode.md | 3 + py-rattler/docs/path_type.md | 3 + py-rattler/docs/paths_entry.md | 3 + py-rattler/docs/paths_json.md | 4 + py-rattler/docs/prefix_placeholder.md | 3 + py-rattler/mkdocs.yml | 5 + py-rattler/rattler/__init__.py | 16 +- py-rattler/rattler/package/__init__.py | 19 +- py-rattler/rattler/package/paths_json.py | 508 +++++++++++++++++++++++ py-rattler/src/lib.rs | 7 + py-rattler/src/paths_json.rs | 320 ++++++++++++++ 12 files changed, 1028 insertions(+), 141 deletions(-) create mode 100644 py-rattler/docs/file_mode.md create mode 100644 py-rattler/docs/path_type.md create mode 100644 py-rattler/docs/paths_entry.md create mode 100644 py-rattler/docs/paths_json.md create mode 100644 py-rattler/docs/prefix_placeholder.md create mode 100644 py-rattler/rattler/package/paths_json.py create mode 100644 py-rattler/src/paths_json.rs diff --git a/py-rattler/Cargo.lock b/py-rattler/Cargo.lock index 260b478cd..1fdc2ed3c 100644 --- a/py-rattler/Cargo.lock +++ b/py-rattler/Cargo.lock @@ -31,9 +31,9 @@ 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", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "async-broadcast" @@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.1.0", + "event-listener 5.2.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -114,7 +114,7 @@ dependencies = [ "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "slab", ] @@ -152,18 +152,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "parking", "polling 3.5.0", - "rustix 0.38.31", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -202,15 +202,15 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.31", + "rustix 0.38.32", "windows-sys 0.48.0", ] [[package]] name = "async-recursion" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" dependencies = [ "proc-macro2", "quote", @@ -223,13 +223,13 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" dependencies = [ - "async-io 2.3.1", + "async-io 2.3.2", "async-lock 2.8.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.31", + "rustix 0.38.32", "signal-hook-registry", "slab", "windows-sys 0.48.0", @@ -243,9 +243,9 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", @@ -293,9 +293,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 = "bitvec" @@ -354,16 +354,16 @@ dependencies = [ "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "piper", "tracing", ] [[package]] name = "bumpalo" -version = "3.15.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" @@ -406,9 +406,9 @@ checksum = "1bf2a5fb3207c12b5d208ebc145f967fea5cac41a021c37417ccc31ba40f39ee" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ "jobserver", "libc", @@ -503,9 +503,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core", "darling_macro", @@ -513,9 +513,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", @@ -527,9 +527,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", @@ -698,9 +698,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -723,7 +723,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.1.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -890,9 +890,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "fastrand 2.0.1", "futures-core", @@ -988,9 +988,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1025,9 +1025,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1058,9 +1058,9 @@ dependencies = [ [[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", @@ -1122,7 +1122,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -1281,9 +1281,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1356,7 +1356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.4", ] [[package]] @@ -1371,7 +1371,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall", ] @@ -1391,7 +1391,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", ] @@ -1419,9 +1419,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" [[package]] name = "md-5" @@ -1499,9 +1499,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", @@ -1662,9 +1662,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" @@ -1672,7 +1672,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1709,9 +1709,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.100" +version = "0.9.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", @@ -1947,7 +1947,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.31", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] @@ -1976,9 +1976,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -2021,7 +2021,7 @@ dependencies = [ "pep508_rs", "pyo3", "pyo3-asyncio", - "pyo3-build-config 0.20.2", + "pyo3-build-config 0.20.3", "rattler", "rattler_conda_types", "rattler_digest", @@ -2083,9 +2083,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07426f0d8fe5a601f26293f300afd1a7b1ed5e78b2a705870c5f30893c5163be" +checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" dependencies = [ "once_cell", "target-lexicon", @@ -2180,7 +2180,7 @@ dependencies = [ [[package]] name = "rattler" -version = "0.19.4" +version = "0.19.5" dependencies = [ "anyhow", "async-compression", @@ -2224,7 +2224,7 @@ dependencies = [ [[package]] name = "rattler_conda_types" -version = "0.20.2" +version = "0.20.3" dependencies = [ "chrono", "fxhash", @@ -2266,7 +2266,7 @@ dependencies = [ [[package]] name = "rattler_index" -version = "0.19.3" +version = "0.19.4" dependencies = [ "fs-err", "rattler_conda_types", @@ -2279,7 +2279,7 @@ dependencies = [ [[package]] name = "rattler_lock" -version = "0.20.2" +version = "0.21.0" dependencies = [ "chrono", "fxhash", @@ -2309,7 +2309,7 @@ dependencies = [ [[package]] name = "rattler_networking" -version = "0.19.2" +version = "0.20.0" dependencies = [ "anyhow", "async-trait", @@ -2338,7 +2338,7 @@ dependencies = [ [[package]] name = "rattler_package_streaming" -version = "0.20.0" +version = "0.20.1" dependencies = [ "bzip2", "chrono", @@ -2363,7 +2363,7 @@ dependencies = [ [[package]] name = "rattler_repodata_gateway" -version = "0.19.3" +version = "0.19.4" dependencies = [ "anyhow", "async-compression", @@ -2401,7 +2401,7 @@ dependencies = [ [[package]] name = "rattler_shell" -version = "0.19.3" +version = "0.19.4" dependencies = [ "enum_dispatch", "indexmap 2.2.5", @@ -2416,7 +2416,7 @@ dependencies = [ [[package]] name = "rattler_solve" -version = "0.20.2" +version = "0.20.3" dependencies = [ "anyhow", "chrono", @@ -2435,7 +2435,7 @@ dependencies = [ [[package]] name = "rattler_virtual_packages" -version = "0.19.3" +version = "0.19.4" dependencies = [ "cfg-if", "libloading", @@ -2476,7 +2476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b1349400e2ffd64a9fb5ed9008e33c0b8ef86bd5bae8f73080839c7082f1d5" dependencies = [ "cfg-if", - "rustix 0.38.31", + "rustix 0.38.32", "windows", ] @@ -2494,9 +2494,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", @@ -2511,9 +2511,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.26" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", "base64", @@ -2559,9 +2559,9 @@ dependencies = [ [[package]] name = "reqwest-middleware" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a3e86aa6053e59030e7ce2d2a3b258dd08fc2d337d52f73f6cb480f5858690" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" dependencies = [ "anyhow", "async-trait", @@ -2580,7 +2580,7 @@ checksum = "2016584c3fd9df0fd859a7dcbc7fafdc7fdd2d87b53a576e8e63e62fad140e33" dependencies = [ "bitvec", "elsa", - "event-listener 5.1.0", + "event-listener 5.2.0", "futures", "itertools", "petgraph", @@ -2635,11 +2635,11 @@ dependencies = [ [[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 0.4.13", @@ -2837,9 +2837,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ "base64", "chrono", @@ -2855,9 +2855,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" +checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" dependencies = [ "darling", "proc-macro2", @@ -2867,9 +2867,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ "indexmap 2.2.5", "itoa", @@ -2962,12 +2962,12 @@ dependencies = [ [[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]] @@ -2996,18 +2996,18 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck", "proc-macro2", @@ -3096,9 +3096,9 @@ 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 = "task-local-extensions" @@ -3117,24 +3117,24 @@ checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand 2.0.1", - "rustix 0.38.31", + "rustix 0.38.32", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -3199,7 +3199,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -3237,9 +3237,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -3370,9 +3370,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", ] @@ -3391,9 +3391,9 @@ checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "unscanny" @@ -3427,9 +3427,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "rand", @@ -3480,9 +3480,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3490,9 +3490,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -3505,9 +3505,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -3517,9 +3517,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3527,9 +3527,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -3540,9 +3540,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" @@ -3559,9 +3559,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -3810,7 +3810,7 @@ checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys 0.4.13", - "rustix 0.38.31", + "rustix 0.38.32", ] [[package]] @@ -3825,15 +3825,15 @@ dependencies = [ [[package]] name = "yansi" -version = "1.0.0-rc.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zbus" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c45d06ae3b0f9ba1fb2671268b975557d8f5a84bb5ec6e43964f87e763d8bca8" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" dependencies = [ "async-broadcast", "async-executor", @@ -3872,9 +3872,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a1ba45ed0ad344b85a2bb5a1fe9830aed23d67812ea39a586e7d0136439c7d" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3886,9 +3886,9 @@ dependencies = [ [[package]] name = "zbus_names" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", @@ -3938,9 +3938,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" dependencies = [ "byteorder", "enumflags2", @@ -3952,9 +3952,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/py-rattler/docs/file_mode.md b/py-rattler/docs/file_mode.md new file mode 100644 index 000000000..6f6295555 --- /dev/null +++ b/py-rattler/docs/file_mode.md @@ -0,0 +1,3 @@ +# FileMode + +::: rattler.package.paths_json.FileMode \ No newline at end of file diff --git a/py-rattler/docs/path_type.md b/py-rattler/docs/path_type.md new file mode 100644 index 000000000..d616cbac1 --- /dev/null +++ b/py-rattler/docs/path_type.md @@ -0,0 +1,3 @@ +# PathType + +::: rattler.package.paths_json.PathType diff --git a/py-rattler/docs/paths_entry.md b/py-rattler/docs/paths_entry.md new file mode 100644 index 000000000..74f80fca6 --- /dev/null +++ b/py-rattler/docs/paths_entry.md @@ -0,0 +1,3 @@ +# PathsEntry + +::: rattler.package.paths_json.PathsEntry diff --git a/py-rattler/docs/paths_json.md b/py-rattler/docs/paths_json.md new file mode 100644 index 000000000..c110f1ca6 --- /dev/null +++ b/py-rattler/docs/paths_json.md @@ -0,0 +1,4 @@ + +# PathsJson + +::: rattler.package.paths_json.PathsJson diff --git a/py-rattler/docs/prefix_placeholder.md b/py-rattler/docs/prefix_placeholder.md new file mode 100644 index 000000000..63fd6e58d --- /dev/null +++ b/py-rattler/docs/prefix_placeholder.md @@ -0,0 +1,3 @@ +# PrefixPlaceholder + +::: rattler.package.paths_json.PrefixPlaceholder \ No newline at end of file diff --git a/py-rattler/mkdocs.yml b/py-rattler/mkdocs.yml index c144dd3fa..f480a9889 100644 --- a/py-rattler/mkdocs.yml +++ b/py-rattler/mkdocs.yml @@ -49,6 +49,11 @@ nav: - metadata: - AboutJson: about_json.md - RunExportsJson: run_exports_json.md + - PathsJson: paths_json.md + - PathsEntry: paths_entry.md + - PathType: path_type.md + - PrefixPlaceholder: prefix_placeholder.md + - FileMode: file_mode.md - IndexJson: index_json.md - match_spec: - MatchSpec: match_spec.md diff --git a/py-rattler/rattler/__init__.py b/py-rattler/rattler/__init__.py index 03d100f99..363d4bd79 100644 --- a/py-rattler/rattler/__init__.py +++ b/py-rattler/rattler/__init__.py @@ -10,7 +10,16 @@ from rattler.channel import Channel, ChannelConfig from rattler.networking import AuthenticatedClient, fetch_repo_data from rattler.virtual_package import GenericVirtualPackage, VirtualPackage -from rattler.package import PackageName, AboutJson, RunExportsJson, IndexJson +from rattler.package import ( + PackageName, + AboutJson, + RunExportsJson, + PathsJson, + PathsEntry, + PathType, + PrefixPlaceholder, + FileMode, +) from rattler.prefix import PrefixRecord, PrefixPaths from rattler.solver import solve from rattler.platform import Platform @@ -62,5 +71,10 @@ "index", "AboutJson", "RunExportsJson", + "PathsJson", + "PathsEntry", + "PathType", + "PrefixPlaceholder", + "FileMode", "IndexJson", ] diff --git a/py-rattler/rattler/package/__init__.py b/py-rattler/rattler/package/__init__.py index 912eba142..acd86b7c8 100644 --- a/py-rattler/rattler/package/__init__.py +++ b/py-rattler/rattler/package/__init__.py @@ -1,6 +1,23 @@ from rattler.package.package_name import PackageName from rattler.package.about_json import AboutJson from rattler.package.run_exports_json import RunExportsJson +from rattler.package.paths_json import ( + PathsJson, + PathsEntry, + PathType, + PrefixPlaceholder, + FileMode, +) from rattler.package.index_json import IndexJson -__all__ = ["PackageName", "AboutJson", "RunExportsJson", "IndexJson"] +__all__ = [ + "PackageName", + "AboutJson", + "RunExportsJson", + "PathsJson", + "PathsEntry", + "PathType", + "PrefixPlaceholder", + "FileMode", + "IndexJson", +] diff --git a/py-rattler/rattler/package/paths_json.py b/py-rattler/rattler/package/paths_json.py new file mode 100644 index 000000000..313f916e9 --- /dev/null +++ b/py-rattler/rattler/package/paths_json.py @@ -0,0 +1,508 @@ +from __future__ import annotations +import os +from pathlib import Path +from typing import List, Optional +from rattler.rattler import ( + PyPathsJson, + PyPathsEntry, + PyPathType, + PyPrefixPlaceholder, + PyFileMode, +) + + +class PathsJson: + """ + A representation of the `paths.json` file found in package archives. + The `paths.json` file contains information about every file included with the package. + """ + + _inner: PyPathsJson + + @staticmethod + def from_package_archive(path: os.PathLike[str]) -> PathsJson: + """ + Parses the package file from archive. + Note: If you want to extract multiple `info/*` files then this will be slightly + slower than manually iterating over the archive entries with + custom logic as this skips over the rest of the archive + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> paths_json + PathsJson() + >>> + ``` + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_package_archive(path)) + + @staticmethod + def from_path(path: os.PathLike[str]) -> PathsJson: + """ + Parses the object from a file specified by a `path`, using a format + appropriate for the file type. + + For example, if the file is in JSON format, this function reads the data + from the file at the specified path, parse the JSON string and return the + resulting object. If the file is not in a parsable format or if the file + could not read, this function returns an error. + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_path(Path(path))) + + @staticmethod + def from_package_directory(path: os.PathLike[str]) -> PathsJson: + """ + Parses the object by looking up the appropriate file from the root of the + specified Conda archive directory, using a format appropriate for the file + type. + + For example, if the file is in JSON format, this function reads the + appropriate file from the archive, parse the JSON string and return the + resulting object. If the file is not in a parsable format or if the file + could not be read, this function returns an error. + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_package_directory(Path(path))) + + @staticmethod + def from_str(string: str) -> PathsJson: + """ + Parses the object from a string, using a format appropriate for the file + type. + + For example, if the file is in JSON format, this function parses the JSON + string and returns the resulting object. If the file is not in a parsable + format, this function returns an error. + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_str(string)) + + @staticmethod + def package_path() -> str: + """ + Returns the path to the file within the Conda archive. + + The path is relative to the root of the archive and includes any necessary + directories. + """ + return PathsJson.package_path() + + @staticmethod + def from_deprecated_package_directory(path: os.PathLike[str]) -> PathsJson: + """ + Constructs a new instance by reading older (deprecated) files from a package directory. + + In older package archives the `paths.json` file does not exist. These packages contain the + information normally present in the `paths.json` file spread over different files in the + archive. + + This function reads the different files and tries to reconstruct a `paths.json` from it. + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_deprecated_package_directory(path)) + + @staticmethod + def from_package_directory_with_deprecated_fallback( + path: os.PathLike[str], + ) -> PathsJson: + """ + Reads the file from a package archive directory. If the `paths.json` file could not be found + use the `from_deprecated_package_directory` method as a fallback. + """ + return PathsJson._from_py_paths_json(PyPathsJson.from_package_directory_with_deprecated_fallback(path)) + + @property + def paths(self) -> List[PathsEntry]: + """ + All entries included in the package. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> paths_json.paths + [PathsEntry(), ...] + >>> + ``` + """ + return [PathsEntry._from_py_paths_entry(path) for path in self._inner.paths] + + @property + def paths_version(self) -> int: + """ + The version of the file. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> paths_json.paths_version + 1 + >>> + ``` + """ + return self._inner.paths_version + + @classmethod + def _from_py_paths_json(cls, py_paths_json: PyPathsJson) -> PathsJson: + paths_json = cls.__new__(cls) + paths_json._inner = py_paths_json + + return paths_json + + def __repr__(self) -> str: + """ + Returns a representation of the PathsJson. + """ + return "PathsJson()" + + +class PathsEntry: + """ + A single entry in the `paths.json` file. + """ + + _inner: PyPathsEntry + + @property + def relative_path(self) -> str: + """ + The relative path from the root of the package. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.relative_path + 'bin/2to3' + >>> + ``` + """ + return self._inner.relative_path + + @property + def no_link(self) -> bool: + """ + Whether or not this file should be linked or not when installing the package. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.no_link + False + >>> + ``` + """ + return self._inner.no_link + + @property + def path_type(self) -> PathType: + """ + Determines how to include the file when installing the package. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.path_type + PathType() + >>> + ``` + """ + return PathType._from_py_path_type(self._inner.path_type) + + @property + def prefix_placeholder(self) -> Optional[PrefixPlaceholder]: + """ + Optionally the placeholder prefix used in the file. If this value is `None` + the prefix is not present in the file. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.prefix_placeholder + >>> + ``` + """ + if placeholder := self._inner.prefix_placeholder: + return PrefixPlaceholder._from_py_prefix_placeholder(placeholder) + + return None + + @property + def sha256(self) -> Optional[bytes]: + """ + A hex representation of the SHA256 hash of the contents of the file. + This entry is only present in version 1 of the paths.json file. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.sha256.hex() + '863589436be82be20e3efbe0e36f20510747b1892b3cbcb398c4c48ad7e96fcc' + >>> + ``` + """ + return self._inner.sha256 + + @property + def size_in_bytes(self) -> Optional[int]: + """ + The size of the file in bytes. + This entry is only present in version 1 of the paths.json file. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> entry.size_in_bytes + 347 + >>> + ``` + """ + if size := self._inner.size_in_bytes: + return size + + return None + + @classmethod + def _from_py_paths_entry(cls, py_paths_entry: PyPathsEntry) -> PathsEntry: + paths_entry = cls.__new__(cls) + paths_entry._inner = py_paths_entry + + return paths_entry + + def __repr__(self) -> str: + """ + Returns a representation of the PathsEntry. + """ + return "PathsEntry()" + + +class PathType: + """ + The path type of the path entry + """ + + _inner: PyPathType + + @property + def hardlink(self) -> bool: + """ + The path should be hard linked (the default). + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> path_type = entry.path_type + >>> path_type.hardlink + False + >>> + ``` + """ + return self._inner.hardlink + + @property + def softlink(self) -> bool: + """ + The path should be soft linked. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> path_type = entry.path_type + >>> path_type.softlink + True + >>> + ``` + """ + return self._inner.softlink + + @property + def directory(self) -> bool: + """ + This should explicitly create an empty directory. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/with-symlinks/python-3.10.6-h2c4edbf_0_cpython.tar.bz2" + ... ) + >>> entry = paths_json.paths[0] + >>> path_type = entry.path_type + >>> path_type.directory + False + >>> + ``` + """ + return self._inner.directory + + @classmethod + def _from_py_path_type(cls, py_paths_type: PyPathType) -> PathType: + path_type = cls.__new__(cls) + path_type._inner = py_paths_type + + return path_type + + def __repr__(self) -> str: + """ + Returns a representation of the PathType. + """ + return "PathType()" + + +class PrefixPlaceholder: + """ + Description off a placeholder text found in a file that must be replaced + when installing the file into the prefix. + """ + + _inner: PyPrefixPlaceholder + + @property + def file_mode(self) -> FileMode: + """ + The type of the file, either binary or text. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/conda-22.9.0-py38haa244fe_2.tar.bz2" + ... ) + >>> entry = paths_json.paths[-1] + >>> entry.prefix_placeholder.file_mode + FileMode() + >>> + ``` + """ + return FileMode._from_py_file_mode(self._inner.file_mode) + + @property + def placeholder(self) -> str: + """ + The placeholder prefix used in the file. This is the path of the + prefix when the package was build. + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/conda-22.9.0-py38haa244fe_2.tar.bz2" + ... ) + >>> entry = paths_json.paths[-1] + >>> entry.prefix_placeholder.placeholder + 'D:\\\\bld\\\\conda_1667595064120\\\\_h_env' + >>> + ``` + """ + return self._inner.placeholder + + @classmethod + def _from_py_prefix_placeholder(cls, py_prefix_placeholder: PyPrefixPlaceholder) -> PrefixPlaceholder: + prefix_placeholder = cls.__new__(cls) + prefix_placeholder._inner = py_prefix_placeholder + + return prefix_placeholder + + def __repr__(self) -> str: + """ + Returns a representation of the PrefixPlaceholder. + """ + return "PrefixPlaceholder()" + + +class FileMode: + """ + The file mode of the entry. + """ + + _inner: PyFileMode + + @property + def binary(self) -> bool: + """ + The file is a binary file (needs binary prefix replacement). + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/conda-22.9.0-py38haa244fe_2.tar.bz2" + ... ) + >>> entry = paths_json.paths[-1] + >>> file_mode = entry.prefix_placeholder.file_mode + >>> file_mode.binary + False + >>> + ``` + """ + return self._inner.binary + + @property + def text(self) -> bool: + """ + The file is a text file (needs text prefix replacement). + + Examples + -------- + ```python + >>> paths_json = PathsJson.from_package_archive( + ... "../test-data/conda-22.9.0-py38haa244fe_2.tar.bz2" + ... ) + >>> entry = paths_json.paths[-1] + >>> file_mode = entry.prefix_placeholder.file_mode + >>> file_mode.text + True + >>> + ``` + """ + return self._inner.text + + @classmethod + def _from_py_file_mode(cls, py_file_mode: PyFileMode) -> FileMode: + file_mode = cls.__new__(cls) + file_mode._inner = py_file_mode + + return file_mode + + def __repr__(self) -> str: + """ + Returns a representation of the FileMode. + """ + return "FileMode()" diff --git a/py-rattler/src/lib.rs b/py-rattler/src/lib.rs index 03503e8b5..009c5beff 100644 --- a/py-rattler/src/lib.rs +++ b/py-rattler/src/lib.rs @@ -10,6 +10,7 @@ mod meta; mod nameless_match_spec; mod networking; mod package_name; +mod paths_json; mod platform; mod prefix_paths; mod record; @@ -41,6 +42,7 @@ use match_spec::PyMatchSpec; use nameless_match_spec::PyNamelessMatchSpec; use networking::{authenticated_client::PyAuthenticatedClient, py_fetch_repo_data}; use package_name::PyPackageName; +use paths_json::{PyFileMode, PyPathType, PyPathsEntry, PyPathsJson, PyPrefixPlaceholder}; use prefix_paths::PyPrefixPaths; use repo_data::{patch_instructions::PyPatchInstructions, sparse::PySparseRepoData, PyRepoData}; use run_exports_json::PyRunExportsJson; @@ -102,6 +104,11 @@ fn rattler(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::().unwrap(); m.add_class::().unwrap(); + m.add_class::().unwrap(); + m.add_class::().unwrap(); + m.add_class::().unwrap(); + m.add_class::().unwrap(); + m.add_class::().unwrap(); m.add_class::().unwrap(); m.add_function(wrap_pyfunction!(py_solve, m).unwrap()) diff --git a/py-rattler/src/paths_json.rs b/py-rattler/src/paths_json.rs new file mode 100644 index 000000000..748367b50 --- /dev/null +++ b/py-rattler/src/paths_json.rs @@ -0,0 +1,320 @@ +use std::path::PathBuf; + +use pyo3::{pyclass, pymethods, types::PyBytes, PyResult, Python}; +use rattler_conda_types::package::{ + FileMode, PackageFile, PathType, PathsEntry, PathsJson, PrefixPlaceholder, +}; +use rattler_package_streaming::seek::read_package_file; + +use crate::error::PyRattlerError; + +/// A representation of the `paths.json` file found in package archives. +/// +/// The `paths.json` file contains information about every file included with the package. +#[pyclass] +#[repr(transparent)] +#[derive(Clone)] +pub struct PyPathsJson { + pub(crate) inner: PathsJson, +} + +impl From for PyPathsJson { + fn from(value: PathsJson) -> Self { + Self { inner: value } + } +} + +impl From for PathsJson { + fn from(value: PyPathsJson) -> Self { + value.inner + } +} + +#[pymethods] +impl PyPathsJson { + /// Parses the package file from archive. + /// Note: If you want to extract multiple `info/*` files then this will be slightly + /// slower than manually iterating over the archive entries with + /// custom logic as this skips over the rest of the archive + #[staticmethod] + pub fn from_package_archive(path: PathBuf) -> PyResult { + Ok(read_package_file::(path) + .map(Into::into) + .map_err(PyRattlerError::from)?) + } + + /// Parses the object from a file specified by a `path`, using a format appropriate for the file + /// type. + /// + /// For example, if the file is in JSON format, this function reads the data from the file at + /// the specified path, parse the JSON string and return the resulting object. If the file is + /// not in a parsable format or if the file could not read, this function returns an error. + #[staticmethod] + pub fn from_path(path: PathBuf) -> PyResult { + Ok(PathsJson::from_path(path) + .map(Into::into) + .map_err(PyRattlerError::from)?) + } + + /// Parses the object by looking up the appropriate file from the root of the specified Conda + /// archive directory, using a format appropriate for the file type. + /// + /// For example, if the file is in JSON format, this function reads the appropriate file from + /// the archive, parse the JSON string and return the resulting object. If the file is not in a + /// parsable format or if the file could not be read, this function returns an error. + #[staticmethod] + pub fn from_package_directory(path: PathBuf) -> PyResult { + Ok(PathsJson::from_package_directory(path) + .map(Into::into) + .map_err(PyRattlerError::from)?) + } + + /// Parses the object from a string, using a format appropriate for the file type. + /// + /// For example, if the file is in JSON format, this function parses the JSON string and returns + /// the resulting object. If the file is not in a parsable format, this function returns an + /// error. + #[staticmethod] + pub fn from_str(str: &str) -> PyResult { + Ok(PathsJson::from_str(str) + .map(Into::into) + .map_err(PyRattlerError::from)?) + } + + /// Returns the path to the file within the Conda archive. + /// + /// The path is relative to the root of the archive and include any necessary directories. + #[staticmethod] + pub fn package_path() -> PathBuf { + PathsJson::package_path().to_owned() + } + + /// Constructs a new instance by reading older (deprecated) files from a package directory. + /// + /// In older package archives the `paths.json` file does not exist. These packages contain the + /// information normally present in the `paths.json` file spread over different files in the + /// archive. + /// + /// This function reads the different files and tries to reconstruct a `paths.json` from it. + #[staticmethod] + pub fn from_deprecated_package_directory(path: PathBuf) -> PyResult { + Ok(PathsJson::from_deprecated_package_directory(&path) + .map(Into::into) + .map_err(PyRattlerError::from)?) + } + + /// Reads the file from a package archive directory. If the `paths.json` file could not be found + /// use the `from_deprecated_package_directory` method as a fallback. + #[staticmethod] + pub fn from_package_directory_with_deprecated_fallback(path: PathBuf) -> PyResult { + Ok( + PathsJson::from_package_directory_with_deprecated_fallback(&path) + .map(Into::into) + .map_err(PyRattlerError::from)?, + ) + } + + /// All entries included in the package. + #[getter] + pub fn paths(&self) -> Vec { + self.inner + .paths + .clone() + .into_iter() + .map(Into::into) + .collect() + } + + /// The version of the file. + #[getter] + pub fn paths_version(&self) -> u64 { + self.inner.paths_version + } +} + +/// A single entry in the `paths.json` file. +#[pyclass] +#[repr(transparent)] +#[derive(Clone)] +pub struct PyPathsEntry { + pub(crate) inner: PathsEntry, +} + +impl From for PyPathsEntry { + fn from(value: PathsEntry) -> Self { + Self { inner: value } + } +} + +impl From for PathsEntry { + fn from(value: PyPathsEntry) -> Self { + value.inner + } +} + +#[pymethods] +impl PyPathsEntry { + /// The relative path from the root of the package + #[getter] + pub fn relative_path(&self) -> PathBuf { + self.inner.relative_path.clone() + } + + /// Whether or not this file should be linked or not when installing the package. + #[getter] + pub fn no_link(&self) -> bool { + self.inner.no_link + } + + /// Determines how to include the file when installing the package + #[getter] + pub fn path_type(&self) -> PyPathType { + self.inner.path_type.into() + } + + /// Optionally the placeholder prefix used in the file. If this value is `None` the prefix is not + /// present in the file. + #[getter] + pub fn prefix_placeholder(&self) -> Option { + if let Some(placeholder) = self.inner.prefix_placeholder.clone() { + return Some(placeholder.into()); + } + + None + } + + /// A hex representation of the SHA256 hash of the contents of the file. + /// This entry is only present in version 1 of the paths.json file. + #[getter] + pub fn sha256<'a>(&self, py: Python<'a>) -> Option<&'a PyBytes> { + self.inner.sha256.map(|sha| PyBytes::new(py, &sha)) + } + + /// The size of the file in bytes + /// This entry is only present in version 1 of the paths.json file. + #[getter] + pub fn size_in_bytes(&self) -> Option { + self.inner.size_in_bytes + } +} + +/// The path type of the path entry +// TODO: Expose this properly later. +#[pyclass] +#[repr(transparent)] +#[derive(Clone)] +pub struct PyPathType { + pub(crate) inner: PathType, +} + +impl From for PyPathType { + fn from(value: PathType) -> Self { + Self { inner: value } + } +} + +impl From for PathType { + fn from(value: PyPathType) -> Self { + value.inner + } +} + +#[pymethods] +impl PyPathType { + /// The path should be hard linked (the default) + #[getter] + pub fn hardlink(&self) -> bool { + matches!(&self.inner, PathType::HardLink) + } + + /// The path should be soft linked + #[getter] + pub fn softlink(&self) -> bool { + matches!(&self.inner, PathType::SoftLink) + } + + /// This should explicitly create an empty directory + #[getter] + pub fn directory(&self) -> bool { + matches!(&self.inner, PathType::Directory) + } +} + +/// Description off a placeholder text found in a file that must be replaced when installing the +/// file into the prefix. +#[pyclass] +#[repr(transparent)] +#[derive(Clone)] +pub struct PyPrefixPlaceholder { + pub(crate) inner: PrefixPlaceholder, +} + +impl From for PyPrefixPlaceholder { + fn from(value: PrefixPlaceholder) -> Self { + Self { inner: value } + } +} + +impl From for PrefixPlaceholder { + fn from(value: PyPrefixPlaceholder) -> Self { + value.inner + } +} + +#[pymethods] +impl PyPrefixPlaceholder { + /// The type of the file, either binary or text. Depending on the type of file either text + /// replacement is performed or CString replacement. + #[getter] + pub fn file_mode(&self) -> PyFileMode { + self.inner.file_mode.into() + } + + /// The placeholder prefix used in the file. This is the path of the prefix when the package + /// was build. + #[getter] + pub fn placeholder(&self) -> String { + self.inner.placeholder.clone() + } +} + +/// The file mode of the entry +#[pyclass] +#[repr(transparent)] +#[derive(Clone)] +pub struct PyFileMode { + pub(crate) inner: FileMode, +} + +impl From for PyFileMode { + fn from(value: FileMode) -> Self { + Self { inner: value } + } +} + +impl From for FileMode { + fn from(value: PyFileMode) -> Self { + value.inner + } +} + +#[pymethods] +impl PyFileMode { + /// The file is a binary file (needs binary prefix replacement) + #[getter] + pub fn binary(&self) -> bool { + match &self.inner { + FileMode::Binary => true, + FileMode::Text => false, + } + } + + /// The file is a text file (needs text prefix replacement) + #[getter] + pub fn text(&self) -> bool { + match &self.inner { + FileMode::Text => true, + FileMode::Binary => false, + } + } +}