diff --git a/Cargo.lock b/Cargo.lock index 4f92b83..2a80d03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,270 +2,11 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix-codec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" -dependencies = [ - "bitflags 2.5.0", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-cors" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" -dependencies = [ - "actix-utils", - "actix-web", - "derive_more", - "futures-util", - "log", - "once_cell", - "smallvec", -] - -[[package]] -name = "actix-governor" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2e7b88f3804e01bd4191fdb08650430bbfcb43d3d9b2890064df3551ec7d25b" -dependencies = [ - "actix-http", - "actix-web", - "futures", - "governor", -] - -[[package]] -name = "actix-http" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "ahash", - "base64 0.21.7", - "bitflags 2.5.0", - "brotli 3.5.0", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "flate2", - "futures-core", - "h2 0.3.26", - "http 0.2.12", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand", - "sha1 0.10.6", - "smallvec", - "tokio", - "tokio-util", - "tracing", - "zstd 0.13.0", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn 2.0.63", -] - -[[package]] -name = "actix-multipart" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b960e2aea75f49c8f069108063d12a48d329fc8b60b786dfc7552a9d5918d2d" -dependencies = [ - "actix-multipart-derive", - "actix-utils", - "actix-web", - "bytes", - "derive_more", - "futures-core", - "futures-util", - "httparse", - "local-waker", - "log", - "memchr", - "mime", - "serde", - "serde_json", - "serde_plain", - "tempfile", - "tokio", -] - -[[package]] -name = "actix-multipart-derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0a77f836d869f700e5b47ac7c3c8b9c8bc82e4aec861954c6198abee3ebd4d" -dependencies = [ - "darling", - "parse-size", - "proc-macro2", - "quote", - "syn 2.0.63", -] - -[[package]] -name = "actix-router" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" -dependencies = [ - "bytestring", - "http 0.2.12", - "regex", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.7", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" -dependencies = [ - "futures-core", - "paste", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "ahash", - "bytes", - "bytestring", - "cfg-if", - "cookie 0.16.2", - "derive_more", - "encoding_rs", - "futures-core", - "futures-util", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.5.7", - "time 0.3.36", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn 2.0.63", -] - -[[package]] -name = "actix-web-httpauth" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" -dependencies = [ - "actix-utils", - "actix-web", - "base64 0.21.7", - "futures-core", - "futures-util", - "log", - "pin-project-lite", -] - [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -276,18 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] - [[package]] name = "aes" version = "0.8.4" @@ -295,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher 0.4.4", + "cipher", "cpufeatures", ] @@ -306,7 +35,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -321,21 +49,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.18" @@ -389,9 +102,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -408,9 +121,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] [[package]] name = "arc-swap" @@ -418,120 +140,44 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "async-broadcast" -version = "0.5.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "event-listener 2.5.3", + "event-listener", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-channel" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] -[[package]] -name = "async-compression" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" -dependencies = [ - "brotli 6.0.0", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-executor" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", - "slab", -] - -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "blocking", - "futures-lite 1.13.0", -] - [[package]] name = "async-io" -version = "1.13.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" -dependencies = [ - "async-lock 3.3.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.0", - "rustix 0.38.34", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.52.0", @@ -539,39 +185,33 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" -dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener", + "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-process" -version = "1.8.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" dependencies = [ - "async-io 1.13.0", - "async-lock 2.8.0", + "async-channel", + "async-io", + "async-lock", "async-signal", + "async-task", "blocking", "cfg-if", - "event-listener 3.1.0", - "futures-lite 1.13.0", - "rustix 0.38.34", - "windows-sys 0.48.0", + "event-listener", + "futures-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -582,22 +222,22 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] name = "async-signal" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" dependencies = [ - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io", + "async-lock", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.34", + "rustix", "signal-hook-registry", "slab", "windows-sys 0.52.0", @@ -611,13 +251,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] @@ -626,17 +266,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "auth-git2" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51bd0e4592409df8631ca807716dc1e5caafae5d01ce0157c966c71c7e49c3c" -dependencies = [ - "dirs 5.0.1", - "git2", - "terminal-prompt", -] - [[package]] name = "autocfg" version = "1.3.0" @@ -645,9 +274,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -658,42 +287,12 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" - [[package]] name = "bitflags" version = "1.3.2" @@ -702,41 +301,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bitpacking" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c7d2ac73c167c06af4a5f37e6e59d84148d57ccbe4480b76f0273eefea82d7" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ - "crunchy", -] - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq 0.1.5", -] - -[[package]] -name = "blake3" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" -dependencies = [ - "arrayref", - "arrayvec 0.7.4", - "cc", - "cfg-if", - "constant_time_eq 0.3.0", + "serde", ] [[package]] @@ -748,78 +317,28 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-modes" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" -dependencies = [ - "block-padding", - "cipher 0.3.0", -] - [[package]] name = "block-padding" -version = "0.2.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel", - "async-lock 3.3.0", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] -[[package]] -name = "brotli" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 2.5.1", -] - -[[package]] -name = "brotli" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 4.0.0", -] - -[[package]] -name = "brotli-decompressor" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bstr" version = "1.9.1" @@ -827,6 +346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", + "regex-automata", "serde", ] @@ -842,12 +362,6 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" - [[package]] name = "byteorder" version = "1.5.0" @@ -860,15 +374,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "bytestring" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" -dependencies = [ - "bytes", -] - [[package]] name = "bzip2" version = "0.4.4" @@ -891,22 +396,25 @@ dependencies = [ ] [[package]] -name = "cc" -version = "1.0.97" +name = "cbc" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907d8581360765417f8f2e0e7d602733bbed60156b4465b7617243689ef9b83d" dependencies = [ "jobserver", "libc", "once_cell", ] -[[package]] -name = "census" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" - [[package]] name = "cfg-if" version = "1.0.0" @@ -915,15 +423,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -931,31 +439,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.5", -] - -[[package]] -name = "chrono_lc" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809c968b91b4949802fba00279fd0610158cbb2ae5f10663f0c3d5331f88d6d6" -dependencies = [ - "chrono", - "lazy_static", - "num-integer", - "serde", - "serde_derive", - "serde_json", - "walkdir", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", + "windows-targets 0.52.6", ] [[package]] @@ -970,9 +454,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" dependencies = [ "clap_builder", "clap_derive", @@ -980,42 +464,39 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] -name = "clipboard-win" -version = "5.3.1" +name = "clru" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" -dependencies = [ - "error-code", -] +checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" [[package]] name = "colorchoice" @@ -1023,6 +504,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1045,18 +536,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "const_fn" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.3.0" @@ -1069,27 +548,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "cookie" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6e25dfc584d06a3dbf775d207ff00d7de98d824c952dd2233dfbb261889a42" -dependencies = [ - "time 0.2.27", - "version_check", -] - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time 0.3.36", - "version_check", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -1116,21 +574,27 @@ dependencies = [ ] [[package]] -name = "crc32fast" -version = "1.4.0" +name = "crc" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ - "cfg-if", + "crc-catalog", ] [[package]] -name = "crossbeam-channel" -version = "0.5.12" +name = "crc-catalog" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "crossbeam-utils", + "cfg-if", ] [[package]] @@ -1154,9 +618,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" @@ -1183,12 +647,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -1201,9 +659,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -1211,57 +669,63 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.63", + "strsim", + "syn 2.0.71", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] -name = "dashmap" -version = "5.5.3" +name = "dbus" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "dbus-secret-service" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3ae92ba157c1fd7e3453bf8fad9cd2e62783fe5f65047fd3b52fcbf6594aef" +dependencies = [ + "aes", + "block-padding", + "cbc", + "dbus", + "futures-util", + "hkdf", + "num", "once_cell", - "parking_lot_core", + "rand", + "sha2", ] [[package]] -name = "data-encoding" -version = "2.6.0" +name = "deflate64" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "serde", - "uuid", -] +checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d" [[package]] name = "deranged" @@ -1274,40 +738,27 @@ dependencies = [ ] [[package]] -name = "derivative" -version = "2.2.0" +name = "derive_arbitrary" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.71", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 1.0.109", -] - -[[package]] -name = "dialoguer" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" -dependencies = [ - "console", - "shell-words", - "tempfile", - "thiserror", - "zeroize", + "rustc_version", + "syn 2.0.71", ] [[package]] @@ -1330,26 +781,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -1358,27 +789,20 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users 0.4.5", + "redox_users", "windows-sys 0.48.0", ] [[package]] -name = "discard" -version = "1.0.4" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] [[package]] name = "dunce" @@ -1392,12 +816,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" -[[package]] -name = "either" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" - [[package]] name = "encode_unicode" version = "0.3.6" @@ -1414,16 +832,16 @@ dependencies = [ ] [[package]] -name = "endian-type" -version = "0.1.2" +name = "endi" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", "serde", @@ -1431,23 +849,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", -] - -[[package]] -name = "env_filter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" -dependencies = [ - "log", - "regex", + "syn 2.0.71", ] [[package]] @@ -1463,34 +871,12 @@ dependencies = [ "termcolor", ] -[[package]] -name = "env_logger" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "erased-serde" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" -dependencies = [ - "serde", -] - [[package]] name = "errno" version = "0.3.9" @@ -1501,85 +887,32 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "error-code" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" - [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener", "pin-project-lite", ] [[package]] -name = "fastdivide" -version = "0.4.1" +name = "faster-hex" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59668941c55e5c186b8b58c391629af56774ec768f73c08bbcd56f09348eb00b" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" [[package]] name = "fastrand" @@ -1587,17 +920,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" -[[package]] -name = "fd-lock" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" -dependencies = [ - "cfg-if", - "rustix 0.38.34", - "windows-sys 0.52.0", -] - [[package]] name = "filetime" version = "0.2.23" @@ -1610,18 +932,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "findshlibs" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" -dependencies = [ - "cc", - "lazy_static", - "libc", - "winapi", -] - [[package]] name = "flate2" version = "1.0.30" @@ -1638,21 +948,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1662,31 +957,19 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs4" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" -dependencies = [ - "rustix 0.38.34", - "windows-sys 0.48.0", -] - [[package]] name = "full_moon" -version = "0.19.0" +version = "1.0.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ef4f8ad0689d3a86bb483650422d72e6f79a37fdc83ed5426cafe96b776ce1" +checksum = "1c23cbff7830f7a5370221b5c073bafc74b5d9e8555873b1f153a41416837e4e" dependencies = [ "bytecount", "cfg-if", "derive_more", "full_moon_derive", - "logos", "paste", "serde", "smol_str", - "stacker", ] [[package]] @@ -1701,21 +984,6 @@ dependencies = [ "syn 1.0.109", ] -[[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" @@ -1732,45 +1000,19 @@ 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-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -1785,7 +1027,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] @@ -1800,19 +1042,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" 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", @@ -1839,20 +1074,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" dependencies = [ - "byteorder 1.5.0", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", + "byteorder", ] [[package]] @@ -1865,17 +1087,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -1884,41 +1095,787 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] -name = "git2" -version = "0.18.3" +name = "gix" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" +checksum = "984c5018adfa7a4536ade67990b3ebc6e11ab57b3d6cd9968de0947ca99b4b06" dependencies = [ - "bitflags 2.5.0", + "gix-actor", + "gix-attributes", + "gix-command", + "gix-commitgraph", + "gix-config", + "gix-credentials", + "gix-date", + "gix-diff", + "gix-discover", + "gix-features", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-macros", + "gix-mailmap", + "gix-negotiate", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-pathspec", + "gix-prompt", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-revwalk", + "gix-sec", + "gix-submodule", + "gix-tempfile", + "gix-trace", + "gix-transport", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", + "once_cell", + "parking_lot", + "regex", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-actor" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b8ee65074b2bbb91d9d97c15d172ea75043aefebf9869b5b329149dc76501c" +dependencies = [ + "bstr", + "gix-date", + "gix-utils", + "itoa", + "serde", + "thiserror", + "winnow 0.6.13", +] + +[[package]] +name = "gix-attributes" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eefb48f42eac136a4a0023f49a54ec31be1c7a9589ed762c45dcb9b953f7ecc8" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "serde", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-chunk" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c8751169961ba7640b513c3b24af61aa962c967aaf04116734975cd5af0c52" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-command" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c22e086314095c43ffe5cdc5c0922d5439da4fd726f3b0438c56147c34dc225" +dependencies = [ + "bstr", + "gix-path", + "gix-trace", + "shell-words", +] + +[[package]] +name = "gix-commitgraph" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b102311085da4af18823413b5176d7c500fb2272eaf391cfa8635d8bcb12c4" +dependencies = [ + "bstr", + "gix-chunk", + "gix-features", + "gix-hash", + "memmap2", + "serde", + "thiserror", +] + +[[package]] +name = "gix-config" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fafe42957e11d98e354a66b6bd70aeea00faf2f62dd11164188224a507c840" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr", + "once_cell", + "smallvec", + "thiserror", + "unicode-bom", + "winnow 0.6.13", +] + +[[package]] +name = "gix-config-value" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "gix-path", "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", + "thiserror", +] + +[[package]] +name = "gix-credentials" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c70146183bd3c7119329a3c7392d1aa0e0adbe48d727f4df31828fe6d8fdaa1" +dependencies = [ + "bstr", + "gix-command", + "gix-config-value", + "gix-path", + "gix-prompt", + "gix-sec", + "gix-trace", + "gix-url", + "serde", + "thiserror", +] + +[[package]] +name = "gix-date" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" +dependencies = [ + "bstr", + "itoa", + "serde", + "thiserror", + "time", +] + +[[package]] +name = "gix-diff" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9bd8b2d07b6675a840b56a6c177d322d45fa082672b0dad8f063b25baf0a4" +dependencies = [ + "bstr", + "gix-hash", + "gix-object", + "thiserror", +] + +[[package]] +name = "gix-discover" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc27c699b63da66b50d50c00668bc0b7e90c3a382ef302865e891559935f3dbf" +dependencies = [ + "bstr", + "dunce", + "gix-fs", + "gix-hash", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror", +] + +[[package]] +name = "gix-features" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac7045ac9fe5f9c727f38799d002a7ed3583cd777e3322a7c4b43e3cf437dc69" +dependencies = [ + "bytes", + "crc32fast", + "flate2", + "gix-hash", + "gix-trace", + "gix-utils", + "libc", + "once_cell", + "prodash", + "sha1_smol", + "thiserror", + "walkdir", +] + +[[package]] +name = "gix-filter" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ce6ea5ac8fca7adbc63c48a1b9e0492c222c386aa15f513405f1003f2f4ab2" +dependencies = [ + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash", + "gix-object", + "gix-packetline-blocking", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-fs" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3338ff92a2164f5209f185ec0cd316f571a72676bb01d27e22f2867ba69f77a" +dependencies = [ + "fastrand", + "gix-features", + "gix-utils", +] + +[[package]] +name = "gix-glob" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a29ad0990cf02c48a7aac76ed0dbddeb5a0d070034b83675cc3bbf937eace4" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "gix-features", + "gix-path", + "serde", +] + +[[package]] +name = "gix-hash" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e" +dependencies = [ + "faster-hex", + "serde", + "thiserror", +] + +[[package]] +name = "gix-hashtable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf80e16f3c19ac06ce415a38b8591993d3f73aede049cb561becb5b3a8e242" +dependencies = [ + "gix-hash", + "hashbrown 0.14.5", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640dbeb4f5829f9fc14d31f654a34a0350e43a24e32d551ad130d99bf01f63f1" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "serde", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8c5a5f1c58edcbc5692b174cda2703aba82ed17d7176ff4c1752eb48b1b167" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "filetime", + "fnv", + "gix-bitmap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "gix-utils", + "gix-validate", + "hashbrown 0.14.5", + "itoa", + "libc", + "memmap2", + "rustix", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-lock" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bc7fe297f1f4614774989c00ec8b1add59571dc9b024b4c00acb7dedd4e19d" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror", +] + +[[package]] +name = "gix-macros" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "gix-mailmap" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb2da346958252cbc8656529f5479830a3bc6046f3d86405c9e77f71dfdf7b2" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "serde", + "thiserror", +] + +[[package]] +name = "gix-negotiate" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d57dec54544d155a495e01de947da024471e1825d7d3f2724301c07a310d6184" +dependencies = [ + "bitflags 2.6.0", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-object", + "gix-revwalk", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-object" +version = "0.42.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25da2f46b4e7c2fa7b413ce4dffb87f69eaf89c2057e386491f4c55cadbfe386" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features", + "gix-hash", + "gix-utils", + "gix-validate", + "itoa", + "serde", + "smallvec", + "thiserror", + "winnow 0.6.13", +] + +[[package]] +name = "gix-odb" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92b9790e2c919166865d0825b26cc440a387c175bed1b43a2fa99c0e9d45e98" +dependencies = [ + "arc-swap", + "gix-date", + "gix-features", + "gix-fs", + "gix-hash", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "serde", + "tempfile", + "thiserror", +] + +[[package]] +name = "gix-pack" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8da51212dbff944713edb2141ed7e002eea326b8992070374ce13a6cb610b3" +dependencies = [ + "clru", + "gix-chunk", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "gix-tempfile", + "memmap2", + "parking_lot", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-packetline" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b70486beda0903b6d5b65dfa6e40585098cdf4e6365ca2dff4f74c387354a515" +dependencies = [ + "bstr", + "faster-hex", + "gix-trace", + "thiserror", +] + +[[package]] +name = "gix-packetline-blocking" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31d42378a3d284732e4d589979930d0d253360eccf7ec7a80332e5ccb77e14a" +dependencies = [ + "bstr", + "faster-hex", + "gix-trace", + "thiserror", +] + +[[package]] +name = "gix-path" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca987128ffb056d732bd545db5db3d8b103d252fbf083c2567bb0796876619a4" +dependencies = [ + "bstr", + "gix-trace", + "home", + "once_cell", + "thiserror", +] + +[[package]] +name = "gix-pathspec" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76cab098dc10ba2d89f634f66bf196dea4d7db4bf10b75c7a9c201c55a2ee19" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror", +] + +[[package]] +name = "gix-prompt" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fddabbc7c51c241600ab3c4623b19fa53bde7c1a2f637f61043ed5fcadf000cc" +dependencies = [ + "gix-command", + "gix-config-value", + "parking_lot", + "rustix", + "thiserror", +] + +[[package]] +name = "gix-protocol" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c140d4c6d209048826bad78f021a01b612830f89da356efeb31afe8957f8bee" +dependencies = [ + "bstr", + "gix-credentials", + "gix-date", + "gix-features", + "gix-hash", + "gix-transport", + "gix-utils", + "maybe-async", + "serde", + "thiserror", + "winnow 0.6.13", +] + +[[package]] +name = "gix-quote" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbff4f9b9ea3fa7a25a70ee62f545143abef624ac6aa5884344e70c8b0a1d9ff" +dependencies = [ + "bstr", + "gix-utils", + "thiserror", +] + +[[package]] +name = "gix-ref" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3394a2997e5bc6b22ebc1e1a87b41eeefbcfcff3dbfa7c4bd73cb0ac8f1f3e2e" +dependencies = [ + "gix-actor", + "gix-date", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate", + "memmap2", + "serde", + "thiserror", + "winnow 0.6.13", +] + +[[package]] +name = "gix-refspec" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde848865834a54fe4d9b4573f15d0e9a68eaf3d061b42d3ed52b4b8acf880b2" +dependencies = [ + "bstr", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-revision" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e08f8107ed1f93a83bcfbb4c38084c7cb3f6cd849793f1d5eec235f9b13b2b" +dependencies = [ + "bstr", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "gix-trace", + "serde", + "thiserror", +] + +[[package]] +name = "gix-revwalk" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4181db9cfcd6d1d0fd258e91569dbb61f94cb788b441b5294dd7f1167a3e788f" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-sec" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1" +dependencies = [ + "bitflags 2.6.0", + "gix-path", + "libc", + "serde", + "windows-sys 0.52.0", +] + +[[package]] +name = "gix-submodule" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921cd49924ac14b6611b22e5fb7bbba74d8780dc7ad26153304b64d1272460ac" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-tempfile" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b0e276cd08eb2a22e9f286a4f13a222a01be2defafa8621367515375644b99" +dependencies = [ + "gix-fs", + "libc", + "once_cell", + "parking_lot", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e" + +[[package]] +name = "gix-transport" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb0ffa5f869977f5b9566399154055902f05d7e85c787d5eacf551acdd0c4adf" +dependencies = [ + "base64", + "bstr", + "gix-command", + "gix-credentials", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "reqwest", + "serde", + "thiserror", +] + +[[package]] +name = "gix-traverse" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f20cb69b63eb3e4827939f42c05b7756e3488ef49c25c412a876691d568ee2a0" +dependencies = [ + "bitflags 2.6.0", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-url" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0db829ebdca6180fbe32be7aed393591df6db4a72dbbc0b8369162390954d1cf" +dependencies = [ + "bstr", + "gix-features", + "gix-path", + "home", + "serde", + "thiserror", "url", ] [[package]] -name = "glam" -version = "0.27.0" +name = "gix-utils" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" +checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc" +dependencies = [ + "fastrand", + "unicode-normalization", +] [[package]] -name = "glob" -version = "0.3.1" +name = "gix-validate" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "82c27dd34a49b1addf193c92070bcbf3beaf6e10f16a78544de6372e146a0acf" +dependencies = [ + "bstr", + "thiserror", +] + +[[package]] +name = "gix-worktree" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f6b7de83839274022aff92157d7505f23debf739d257984a300a35972ca94e" +dependencies = [ + "bstr", + "gix-attributes", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-validate", + "serde", +] [[package]] name = "globset" @@ -1929,61 +1886,22 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", -] - -[[package]] -name = "governor" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" -dependencies = [ - "cfg-if", - "dashmap", - "futures", - "futures-timer", - "no-std-compat", - "nonzero_ext", - "parking_lot", - "portable-atomic", - "quanta", - "rand", - "smallvec", - "spinning_top", + "regex-automata", + "regex-syntax", ] [[package]] name = "h2" -version = "0.3.26" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 1.1.0", + "http", "indexmap 2.2.6", "slab", "tokio", @@ -2019,6 +1937,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2052,34 +1976,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hostname" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" -dependencies = [ - "cfg-if", - "libc", - "windows 0.52.0", -] - -[[package]] -name = "htmlescape" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -2093,49 +1989,32 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", + "http", ] [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", - "http 1.1.0", - "http-body 1.0.0", + "futures-util", + "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "humantime" @@ -2145,42 +2024,17 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.7", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.4", - "http 1.1.0", - "http-body 1.0.0", + "h2", + "http", + "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -2190,80 +2044,36 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 0.2.12", - "hyper 0.14.28", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" -dependencies = [ - "futures-util", - "http 1.1.0", - "hyper 1.3.1", + "http", + "hyper", "hyper-util", - "rustls 0.22.4", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.25.0", + "tokio-rustls", "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-tungstenite" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a343d17fe7885302ed7252767dc7bb83609a874b6ff581142241ec4b73957ad" -dependencies = [ - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "pin-project-lite", - "tokio", - "tokio-tungstenite", - "tungstenite", + "webpki-roots", ] [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http", + "http-body", + "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower", "tower-service", @@ -2319,32 +2129,12 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.6", + "regex-automata", "same-file", "walkdir", "winapi-util", ] -[[package]] -name = "include_dir" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" -dependencies = [ - "glob", - "include_dir_macros", -] - -[[package]] -name = "include_dir_macros" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -2353,6 +2143,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -2363,6 +2154,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -2394,6 +2186,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ + "block-padding", "generic-array", ] @@ -2403,7 +2196,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "crossterm", "dyn-clone", "fuzzy-matcher", @@ -2416,25 +2209,11 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", ] [[package]] @@ -2443,41 +2222,42 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[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.11" @@ -2504,12 +2284,12 @@ dependencies = [ [[package]] name = "keyring" -version = "2.3.3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363387f0019d714aa60cc30ab4fe501a747f4c08fc58f069dd14be971bd495a0" +checksum = "f32930aef50aff920e88e6cf66b70a6d587a6f2bae6aeade5c1e583661a40f8e" dependencies = [ - "byteorder 1.5.0", - "lazy_static", + "byteorder", + "dbus-secret-service", "linux-keyutils", "secret-service", "security-framework", @@ -2517,51 +2297,98 @@ dependencies = [ ] [[package]] -name = "language-tags" -version = "0.3.2" +name = "kstring" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "levenshtein_automata" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" - -[[package]] -name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "libgit2-sys" -version = "0.16.2+1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", + "serde", + "static_assertions", ] [[package]] -name = "libloading" -version = "0.8.3" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" dependencies = [ - "cfg-if", - "windows-targets 0.52.5", + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "pkg-config", ] [[package]] @@ -2570,80 +2397,25 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] -[[package]] -name = "libssh2-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "line-wrap" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" - [[package]] name = "linux-keyutils" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "local-channel" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" -dependencies = [ - "futures-core", - "futures-sink", - "local-waker", -] - -[[package]] -name = "local-waker" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2656,205 +2428,53 @@ dependencies = [ ] [[package]] -name = "log" -version = "0.4.21" +name = "lockfree-object-pool" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] -name = "logos" -version = "0.12.1" +name = "log" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" dependencies = [ - "logos-derive", + "byteorder", + "crc", ] [[package]] -name = "logos-derive" -version = "0.12.1" +name = "maybe-async" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ - "beef", - "fnv", "proc-macro2", "quote", - "regex-syntax 0.6.29", - "syn 1.0.109", -] - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "pin-utils", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "lru" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "luau0-src" -version = "0.8.6+luau622" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07758c1f5908f7f9dd9109efaf8c66907cc38acf312db03287e7ad2a64b5de1c" -dependencies = [ - "cc", -] - -[[package]] -name = "lune" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98794d9d507af3f382df7ef137605aac2a4f88eded2c731ce9d59ffafdb4d51" -dependencies = [ - "anyhow", - "async-compression", - "async-trait", - "blocking", - "chrono", - "chrono_lc", - "clap", - "console", - "dialoguer", - "directories", - "dunce", - "env_logger 0.11.3", - "futures-util", - "glam", - "http 1.1.0", - "http-body-util", - "hyper 1.3.1", - "hyper-tungstenite", - "hyper-util", - "include_dir", - "itertools 0.12.1", - "lz4_flex", - "mlua", - "mlua-luau-scheduler", - "once_cell", - "os_str_bytes", - "path-clean", - "pathdiff", - "pin-project", - "rand", - "rbx_binary", - "rbx_cookie", - "rbx_dom_weak", - "rbx_reflection", - "rbx_reflection_database", - "rbx_xml", - "regex", - "reqwest 0.11.27", - "rustyline", - "serde", - "serde_json", - "serde_yaml", - "thiserror", - "tokio", - "tokio-tungstenite", - "toml", - "tracing", - "tracing-subscriber", - "urlencoding", -] - -[[package]] -name = "lz4" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" -dependencies = [ - "libc", - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "lz4_flex" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" -dependencies = [ - "twox-hash", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "measure_time" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbefd235b0aadd181626f281e1d684e116972988c14c264e42069d5e8a5775cc" -dependencies = [ - "instant", - "log", + "syn 2.0.71", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.7.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -2872,25 +2492,19 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -2903,81 +2517,10 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] -[[package]] -name = "mlua" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9bed6bce296397a9d6a86f995dd10a547a4e6949825d45225906bdcbfe7367" -dependencies = [ - "bstr", - "erased-serde", - "futures-util", - "libloading", - "mlua-sys", - "num-traits", - "once_cell", - "rustc-hash", - "serde", - "serde-value", -] - -[[package]] -name = "mlua-luau-scheduler" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13eabdbc57fa38cf0b604d98ce3431573c79a964aac56e09c16c240d36cb1bf" -dependencies = [ - "async-executor", - "blocking", - "concurrent-queue", - "derive_more", - "event-listener 4.0.3", - "futures-lite 2.3.0", - "mlua", - "rustc-hash", - "tracing", -] - -[[package]] -name = "mlua-sys" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16a9ba1dd2c6ac971b204262d434c24d65067038598f0638b64e5dca28d52b8" -dependencies = [ - "cc", - "cfg-if", - "luau0-src", - "pkg-config", -] - -[[package]] -name = "murmurhash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "newline-converter" version = "0.3.0" @@ -2987,69 +2530,32 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - [[package]] name = "nix" -version = "0.26.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.7.1", -] - -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", + "memoffset", ] [[package]] -name = "no-std-compat" -version = "0.4.1" +name = "nondestructive" +version = "0.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "df8c6dda9b7e104ebb1ff495a2c95c9c14bf9ef285328f08617ed2170c681196" dependencies = [ + "bstr", + "itoa", + "lexical-core", "memchr", - "minimal-lexical", -] - -[[package]] -name = "nonzero_ext" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", + "ryu", + "slab", + "twox-hash", ] [[package]] @@ -3068,9 +2574,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -3137,7 +2643,16 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ "libc", ] @@ -3149,9 +2664,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -3163,62 +2678,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "oneshot" -version = "0.1.6" +name = "open" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f6640c6bda7731b1fdbab747981a0f896dd1fedaf9f4a53fa237a04a84431f4" +checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" dependencies = [ - "loom", -] - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", + "is-wsl", "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.63", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "pathdiff", ] [[package]] @@ -3227,15 +2694,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - [[package]] name = "ordered-stream" version = "0.2.0" @@ -3246,41 +2704,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "os_info" -version = "3.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" -dependencies = [ - "log", - "serde", - "windows-sys 0.52.0", -] - -[[package]] -name = "os_str_bytes" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ac44c994af577c799b1b4bd80dc214701e349873ad894d6cdf96f4f7526e0b9" -dependencies = [ - "memchr", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "ownedbytes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8a72b918ae8198abb3a18c190288123e1d442b6b9a7d709305fd194688b4b7" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "parking" version = "2.2.0" @@ -3289,9 +2712,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3305,26 +2728,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", - "windows-targets 0.52.5", -] - -[[package]] -name = "parse-size" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", + "windows-targets 0.52.6", ] [[package]] @@ -3333,12 +2739,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path-clean" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" - [[package]] name = "pathdiff" version = "0.2.1" @@ -3347,14 +2747,12 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "hmac", - "password-hash", - "sha2", ] [[package]] @@ -3365,36 +2763,37 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pesde" -version = "0.4.7" +version = "0.5.0-dev.0" dependencies = [ "anyhow", - "auth-git2", "cfg-if", "chrono", "clap", + "colored", "directories", "flate2", "full_moon", - "futures-executor", - "git2", + "gix", "ignore", "indicatif", "indicatif-log-bridge", "inquire", "keyring", "log", - "lune", + "nondestructive", "once_cell", + "open", "pathdiff", "pretty_env_logger", "relative-path", - "reqwest 0.12.4", - "semver 1.0.23", + "reqwest", + "secrecy", + "semver", "serde", "serde_json", + "serde_with", "serde_yaml", "tar", - "tempfile", "thiserror", "threadpool", "toml", @@ -3402,37 +2801,6 @@ dependencies = [ "zip", ] -[[package]] -name = "pesde-registry" -version = "0.6.1" -dependencies = [ - "actix-cors", - "actix-governor", - "actix-multipart", - "actix-multipart-derive", - "actix-web", - "actix-web-httpauth", - "dotenvy", - "flate2", - "git2", - "log", - "pesde", - "pretty_env_logger", - "reqwest 0.12.4", - "rusty-s3", - "semver 1.0.23", - "sentry", - "sentry-actix", - "sentry-log", - "serde", - "serde_json", - "serde_yaml", - "tantivy", - "tar", - "thiserror", - "zstd-sys", -] - [[package]] name = "pin-project" version = "1.1.5" @@ -3450,7 +2818,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] @@ -3467,12 +2835,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand", "futures-io", ] @@ -3482,47 +2850,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "plist" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" -dependencies = [ - "base64 0.21.7", - "indexmap 2.2.6", - "line-wrap", - "quick-xml 0.31.0", - "serde", - "time 0.3.36", -] - [[package]] name = "polling" -version = "2.8.0" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.34", + "rustix", "tracing", "windows-sys 0.52.0", ] @@ -3551,95 +2889,79 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "env_logger 0.10.2", + "env_logger", "log", ] [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "toml_edit 0.21.1", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] -name = "profiling" -version = "1.0.15" +name = "prodash" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" + +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" dependencies = [ - "profiling-procmacros", + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", ] [[package]] -name = "profiling-procmacros" -version = "1.0.15" +name = "quinn-proto" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" dependencies = [ - "quote", - "syn 2.0.63", + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", ] [[package]] -name = "psm" -version = "0.1.21" +name = "quinn-udp" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" dependencies = [ - "cc", -] - -[[package]] -name = "quanta" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" -dependencies = [ - "crossbeam-utils", "libc", "once_cell", - "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", - "web-sys", - "winapi", -] - -[[package]] -name = "quick-xml" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", + "socket2", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -3651,16 +2973,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rand" version = "0.8.5" @@ -3688,136 +3000,9 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] -[[package]] -name = "raw-cpuid" -version = "11.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" -dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "rbx_binary" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6" -dependencies = [ - "log", - "lz4", - "profiling", - "rbx_dom_weak", - "rbx_reflection", - "rbx_reflection_database", - "thiserror", -] - -[[package]] -name = "rbx_cookie" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a61b073240f4c13b1e780a8999a113dfa28bc93f2cf9fc41c6f36e7aceb5bf" -dependencies = [ - "byteorder 0.5.3", - "cookie 0.15.2", - "dirs 1.0.5", - "log", - "plist", - "winapi", - "winreg 0.10.1", -] - -[[package]] -name = "rbx_dom_weak" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316" -dependencies = [ - "rbx_types", - "serde", -] - -[[package]] -name = "rbx_reflection" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722" -dependencies = [ - "rbx_types", - "serde", - "thiserror", -] - -[[package]] -name = "rbx_reflection_database" -version = "0.2.10+roblox-607" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0" -dependencies = [ - "lazy_static", - "rbx_reflection", - "rmp-serde", - "serde", -] - -[[package]] -name = "rbx_types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c" -dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "blake3", - "lazy_static", - "rand", - "serde", - "thiserror", -] - -[[package]] -name = "rbx_xml" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea" -dependencies = [ - "base64 0.13.1", - "log", - "rbx_dom_weak", - "rbx_reflection", - "rbx_reflection_database", - "xml-rs", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.4.1" @@ -3829,22 +3014,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "bitflags 2.6.0", ] [[package]] @@ -3853,54 +3027,39 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.15", + "getrandom", "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "relative-path" @@ -3913,76 +3072,34 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-rustls 0.24.2", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg 0.50.0", -] - -[[package]] -name = "reqwest" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" -dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-channel", "futures-core", "futures-util", - "h2 0.4.4", - "http 1.1.0", - "http-body 1.0.0", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.3.1", - "hyper-rustls 0.26.0", - "hyper-tls", + "hyper", + "hyper-rustls", "hyper-util", "ipnet", "js-sys", "log", "mime", "mime_guess", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.22.4", - "rustls-pemfile 2.1.2", + "quinn", + "rustls", + "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", @@ -3990,15 +3107,14 @@ dependencies = [ "sync_wrapper", "system-configuration", "tokio", - "tokio-native-tls", - "tokio-rustls 0.25.0", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.1", - "winreg 0.52.0", + "webpki-roots", + "winreg", ] [[package]] @@ -4009,57 +3125,13 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "spin", "untrusted", "windows-sys 0.52.0", ] -[[package]] -name = "rmp" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" -dependencies = [ - "byteorder 1.5.0", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" -dependencies = [ - "byteorder 1.5.0", - "rmp", - "serde", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64 0.13.1", - "blake2b_simd", - "constant_time_eq 0.1.5", - "crossbeam-utils", -] - -[[package]] -name = "rust-stemmers" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" -dependencies = [ - "serde", - "serde_derive", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4072,36 +3144,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.23", -] - -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "semver", ] [[package]] @@ -4110,55 +3159,34 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", + "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.3", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.22.1", + "base64", "rustls-pki-types", ] @@ -4170,72 +3198,15 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" dependencies = [ "ring", "rustls-pki-types", "untrusted", ] -[[package]] -name = "rustversion" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" - -[[package]] -name = "rusty-s3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31aa883f1b986a5249641e574ca0e11ac4fb9970b009c6fbb96fedaf4fa78db8" -dependencies = [ - "base64 0.21.7", - "hmac", - "md-5", - "percent-encoding", - "quick-xml 0.30.0", - "serde", - "serde_json", - "sha2", - "time 0.3.36", - "url", - "zeroize", -] - -[[package]] -name = "rustyline" -version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "clipboard-win", - "fd-lock", - "home", - "libc", - "log", - "memchr", - "nix 0.28.0", - "radix_trie", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "windows-sys 0.52.0", -] - [[package]] name = "ryu" version = "1.0.18" @@ -4251,21 +3222,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -4273,23 +3229,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.1" +name = "secrecy" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ - "ring", - "untrusted", + "zeroize", ] [[package]] name = "secret-service" -version = "3.0.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95" +checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4" dependencies = [ - "aes 0.7.5", - "block-modes", + "aes", + "cbc", "futures-util", "generic-array", "hkdf", @@ -4307,7 +3262,7 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -4324,15 +3279,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.23" @@ -4342,192 +3288,37 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "sentry" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00421ed8fa0c995f07cde48ba6c89e80f2b312f74ff637326f392fbfd23abe02" -dependencies = [ - "httpdate", - "native-tls", - "reqwest 0.12.4", - "sentry-backtrace", - "sentry-contexts", - "sentry-core", - "sentry-debug-images", - "sentry-panic", - "sentry-tracing", - "tokio", - "ureq", -] - -[[package]] -name = "sentry-actix" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1986312ea8425a28299262ead2483ca8f0e167994f9239848d5718041abcd49" -dependencies = [ - "actix-web", - "futures-util", - "sentry-core", -] - -[[package]] -name = "sentry-backtrace" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a79194074f34b0cbe5dd33896e5928bbc6ab63a889bd9df2264af5acb186921e" -dependencies = [ - "backtrace", - "once_cell", - "regex", - "sentry-core", -] - -[[package]] -name = "sentry-contexts" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba8870c5dba2bfd9db25c75574a11429f6b95957b0a78ac02e2970dd7a5249a" -dependencies = [ - "hostname", - "libc", - "os_info", - "rustc_version 0.4.0", - "sentry-core", - "uname", -] - -[[package]] -name = "sentry-core" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a75011ea1c0d5c46e9e57df03ce81f5c7f0a9e199086334a1f9c0a541e0826" -dependencies = [ - "once_cell", - "rand", - "sentry-types", - "serde", - "serde_json", -] - -[[package]] -name = "sentry-debug-images" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec2a486336559414ab66548da610da5e9626863c3c4ffca07d88f7dc71c8de8" -dependencies = [ - "findshlibs", - "once_cell", - "sentry-core", -] - -[[package]] -name = "sentry-log" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74b7261245ff17a8c48e8f3e1e96fb6b84146870121af880d53aef6a5b4f784" -dependencies = [ - "log", - "sentry-core", -] - -[[package]] -name = "sentry-panic" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eaa3ecfa3c8750c78dcfd4637cfa2598b95b52897ed184b4dc77fcf7d95060d" -dependencies = [ - "sentry-backtrace", - "sentry-core", -] - -[[package]] -name = "sentry-tracing" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f715932bf369a61b7256687c6f0554141b7ce097287e30e3f7ed6e9de82498fe" -dependencies = [ - "sentry-backtrace", - "sentry-core", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "sentry-types" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4519c900ce734f7a0eb7aba0869dfb225a7af8820634a7dd51449e3b093cfb7c" -dependencies = [ - "debugid", - "hex", - "rand", - "serde", - "serde_json", - "thiserror", - "time 0.3.36", - "url", - "uuid", -] - [[package]] name = "serde" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ - "indexmap 2.2.6", "itoa", "ryu", "serde", ] -[[package]] -name = "serde_plain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" -dependencies = [ - "serde", -] - [[package]] name = "serde_repr" version = "0.1.19" @@ -4536,14 +3327,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -4560,6 +3351,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -4573,15 +3394,6 @@ dependencies = [ "unsafe-libyaml", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.6" @@ -4610,15 +3422,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shell-words" version = "1.1.0" @@ -4656,13 +3459,10 @@ dependencies = [ ] [[package]] -name = "sketches-ddsketch" -version = "0.2.2" +name = "simd-adler32" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" -dependencies = [ - "serde", -] +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" @@ -4678,6 +3478,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smol_str" @@ -4688,16 +3491,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -4714,104 +3507,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spinning_top" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" -dependencies = [ - "cc", - "cfg-if", - "libc", - "psm", - "winapi", -] - -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -4820,9 +3521,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -4837,9 +3538,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -4848,9 +3549,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "system-configuration" @@ -4873,151 +3574,11 @@ dependencies = [ "libc", ] -[[package]] -name = "tantivy" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6083cd777fa94271b8ce0fe4533772cb8110c3044bab048d20f70108329a1f2" -dependencies = [ - "aho-corasick", - "arc-swap", - "async-trait", - "base64 0.21.7", - "bitpacking", - "byteorder 1.5.0", - "census", - "crc32fast", - "crossbeam-channel", - "downcast-rs", - "fastdivide", - "fs4", - "htmlescape", - "itertools 0.11.0", - "levenshtein_automata", - "log", - "lru", - "lz4_flex", - "measure_time", - "memmap2", - "murmurhash32", - "num_cpus", - "once_cell", - "oneshot", - "rayon", - "regex", - "rust-stemmers", - "rustc-hash", - "serde", - "serde_json", - "sketches-ddsketch", - "smallvec", - "tantivy-bitpacker", - "tantivy-columnar", - "tantivy-common", - "tantivy-fst", - "tantivy-query-grammar", - "tantivy-stacker", - "tantivy-tokenizer-api", - "tempfile", - "thiserror", - "time 0.3.36", - "uuid", - "winapi", -] - -[[package]] -name = "tantivy-bitpacker" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecb164321482301f514dd582264fa67f70da2d7eb01872ccd71e35e0d96655a" -dependencies = [ - "bitpacking", -] - -[[package]] -name = "tantivy-columnar" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d85f8019af9a78b3118c11298b36ffd21c2314bd76bbcd9d12e00124cbb7e70" -dependencies = [ - "fastdivide", - "fnv", - "itertools 0.11.0", - "serde", - "tantivy-bitpacker", - "tantivy-common", - "tantivy-sstable", - "tantivy-stacker", -] - -[[package]] -name = "tantivy-common" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4a3a975e604a2aba6b1106a04505e1e7a025e6def477fab6e410b4126471e1" -dependencies = [ - "async-trait", - "byteorder 1.5.0", - "ownedbytes", - "serde", - "time 0.3.36", -] - -[[package]] -name = "tantivy-fst" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3c506b1a8443a3a65352df6382a1fb6a7afe1a02e871cee0d25e2c3d5f3944" -dependencies = [ - "byteorder 1.5.0", - "regex-syntax 0.6.29", - "utf8-ranges", -] - -[[package]] -name = "tantivy-query-grammar" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d39c5a03100ac10c96e0c8b07538e2ab8b17da56434ab348309b31f23fada77" -dependencies = [ - "nom", -] - -[[package]] -name = "tantivy-sstable" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0c1bb43e5e8b8e05eb8009610344dbf285f06066c844032fbb3e546b3c71df" -dependencies = [ - "tantivy-common", - "tantivy-fst", - "zstd 0.12.4", -] - -[[package]] -name = "tantivy-stacker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2c078595413f13f218cf6f97b23dcfd48936838f1d3d13a1016e05acd64ed6c" -dependencies = [ - "murmurhash32", - "tantivy-common", -] - -[[package]] -name = "tantivy-tokenizer-api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "347b6fb212b26d3505d224f438e3c4b827ab8bd847fe9953ad5ac6b8f9443b66" -dependencies = [ - "serde", -] - [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -5031,8 +3592,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.1.0", - "rustix 0.38.34", + "fastrand", + "rustix", "windows-sys 0.52.0", ] @@ -5045,34 +3606,24 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal-prompt" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572818b3472910acbd5dff46a3413715c18e934b071ab2ba464a7b2c2af16376" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] @@ -5094,21 +3645,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi", -] - [[package]] name = "time" version = "0.3.36" @@ -5117,11 +3653,13 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", - "time-macros 0.2.18", + "time-macros", ] [[package]] @@ -5130,16 +3668,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - [[package]] name = "time-macros" version = "0.2.18" @@ -5150,24 +3678,11 @@ dependencies = [ "time-core", ] -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] - [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5180,82 +3695,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.7", - "tokio-macros", - "tracing", + "socket2", "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 2.0.63", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" -dependencies = [ - "rustls 0.22.4", + "rustls", "rustls-pki-types", "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "rustls 0.22.4", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.25.0", - "tungstenite", - "webpki-roots 0.26.1", -] - [[package]] name = "tokio-util" version = "0.7.11" @@ -5271,31 +3734,30 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ - "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.15", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.2.6", "toml_datetime", @@ -5304,15 +3766,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.13", ] [[package]] @@ -5328,7 +3790,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -5349,7 +3810,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5363,7 +3823,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] @@ -5373,36 +3833,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -5411,27 +3841,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder 1.5.0", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand", - "rustls 0.22.4", - "rustls-pki-types", - "sha1 0.10.6", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "twox-hash" version = "1.6.3" @@ -5439,6 +3848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", + "rand", "static_assertions", ] @@ -5454,20 +3864,11 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset 0.9.1", + "memoffset", "tempfile", "winapi", ] -[[package]] -name = "uname" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" -dependencies = [ - "libc", -] - [[package]] name = "unicase" version = "2.7.0" @@ -5483,6 +3884,12 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -5506,9 +3913,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unsafe-libyaml" @@ -5522,24 +3929,11 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" -dependencies = [ - "base64 0.22.1", - "log", - "native-tls", - "once_cell", - "url", -] - [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -5547,51 +3941,11 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8-ranges" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" - [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom 0.2.15", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -5599,12 +3953,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "waker-fn" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" - [[package]] name = "walkdir" version = "2.5.0" @@ -5624,12 +3972,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5657,7 +3999,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -5691,7 +4033,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5714,15 +4056,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.4" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] @@ -5758,32 +4094,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core", - "windows-targets 0.52.5", -] - [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -5801,7 +4118,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -5821,18 +4138,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "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", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -5843,9 +4160,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -5855,9 +4172,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -5867,15 +4184,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -5885,9 +4202,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -5897,9 +4214,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -5909,9 +4226,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -5921,9 +4238,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -5936,32 +4253,13 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winreg" version = "0.52.0" @@ -5979,61 +4277,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.13", - "rustix 0.38.34", + "linux-raw-sys", + "rustix", ] [[package]] name = "xdg-home" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] -[[package]] -name = "xml-rs" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" - [[package]] name = "zbus" -version = "3.15.2" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +checksum = "851238c133804e0aa888edf4a0229481c753544ca12a60fd1c3230c8a500fe40" dependencies = [ "async-broadcast", - "async-executor", - "async-fs", - "async-io 1.13.0", - "async-lock 2.8.0", "async-process", "async-recursion", - "async-task", "async-trait", - "blocking", - "byteorder 1.5.0", - "derivative", "enumflags2", - "event-listener 2.5.3", + "event-listener", "futures-core", "futures-sink", "futures-util", "hex", - "nix 0.26.4", - "once_cell", + "nix", "ordered-stream", "rand", "serde", "serde_repr", - "sha1 0.10.6", + "sha1", "static_assertions", "tracing", "uds_windows", - "winapi", + "windows-sys 0.52.0", "xdg-home", "zbus_macros", "zbus_names", @@ -6042,23 +4325,22 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.15.2" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +checksum = "8d5a3f12c20bd473be3194af6b49d50d7bb804ef3192dc70eddedb26b85d9da7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "regex", - "syn 1.0.109", + "syn 2.0.71", "zvariant_utils", ] [[package]] name = "zbus_names" -version = "2.6.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", @@ -6067,111 +4349,110 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.71", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] [[package]] name = "zip" -version = "0.6.6" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39" dependencies = [ - "aes 0.8.4", - "byteorder 1.5.0", + "aes", + "arbitrary", "bzip2", - "constant_time_eq 0.1.5", + "constant_time_eq", "crc32fast", "crossbeam-utils", + "deflate64", + "displaydoc", "flate2", "hmac", + "indexmap 2.2.6", + "lzma-rs", + "memchr", "pbkdf2", - "sha1 0.10.6", - "time 0.3.36", - "zstd 0.11.2+zstd.1.5.2", + "rand", + "sha1", + "thiserror", + "time", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", ] [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - -[[package]] -name = "zstd" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" -dependencies = [ - "zstd-safe 6.0.6", -] - -[[package]] -name = "zstd" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" -dependencies = [ - "zstd-safe 7.0.0", + "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-safe" -version = "6.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-safe" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.12+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" dependencies = [ "cc", "pkg-config", @@ -6179,13 +4460,12 @@ dependencies = [ [[package]] name = "zvariant" -version = "3.15.2" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +checksum = "1724a2b330760dc7d2a8402d841119dc869ef120b139d29862d6980e9c75bfc9" dependencies = [ - "byteorder 1.5.0", + "endi", "enumflags2", - "libc", "serde", "static_assertions", "zvariant_derive", @@ -6193,24 +4473,24 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "3.15.2" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +checksum = "55025a7a518ad14518fb243559c058a2e5b848b015e31f1d90414f36e3317859" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.71", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.71", ] diff --git a/Cargo.toml b/Cargo.toml index cf73d18..dca31ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,20 @@ [package] name = "pesde" -version = "0.4.7" +version = "0.5.0-dev.0" edition = "2021" license = "MIT" authors = ["daimond113 "] -description = "A package manager for Roblox" +description = "A package manager for Luau" homepage = "https://pesde.daimond113.com" repository = "https://github.com/daimond113/pesde" include = ["src/**/*", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "CHANGELOG.md"] [features] -bin = ["clap", "directories", "keyring", "anyhow", "ignore", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "lune", "futures-executor", "indicatif", "auth-git2", "indicatif-log-bridge", "inquire", "once_cell"] -wally = ["toml", "zip"] +bin = ["clap", "directories", "ignore", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "indicatif", "indicatif-log-bridge", "inquire", "nondestructive", "colored", "anyhow", "keyring", "open"] +wally-compat = ["toml", "zip"] +roblox = [] +lune = [] +luau = [] [[bin]] name = "pesde" @@ -19,51 +22,46 @@ path = "src/main.rs" required-features = ["bin"] [dependencies] -serde = { version = "1.0.197", features = ["derive"] } -serde_yaml = "0.9.33" -serde_json = "1.0.114" -git2 = "0.18.3" -semver = { version = "1.0.22", features = ["serde"] } -reqwest = { version = "0.12.1", default-features = false, features = ["rustls-tls", "blocking"] } -tar = "0.4.40" -flate2 = "1.0.28" +serde = { version = "1.0.204", features = ["derive"] } +serde_yaml = "0.9.34" +serde_json = "1.0.120" +serde_with = "3.8.3" +gix = { version = "0.63.0", default-features = false, features = ["blocking-http-transport-reqwest-rust-tls", "revparse-regex", "credentials", "serde"] } +semver = { version = "1.0.23", features = ["serde"] } +reqwest = { version = "0.12.5", default-features = false, features = ["rustls-tls", "blocking"] } +tar = "0.4.41" +flate2 = "1.0.30" pathdiff = "0.2.1" -relative-path = { version = "1.9.2", features = ["serde"] } -log = "0.4.21" -thiserror = "1.0.58" +relative-path = { version = "1.9.3", features = ["serde"] } +log = "0.4.22" +thiserror = "1.0.62" threadpool = "1.8.1" -full_moon = { version = "0.19.0", features = ["stacker", "roblox"] } -url = { version = "2.5.0", features = ["serde"] } +full_moon = { version = "1.0.0-rc.5", features = ["luau"] } +url = { version = "2.5.2", features = ["serde"] } cfg-if = "1.0.0" +once_cell = "1.19.0" +secrecy = "0.8.0" +chrono = { version = "0.4.38", features = ["serde"] } -toml = { version = "0.8.12", optional = true } -zip = { version = "0.6.6", optional = true } +toml = { version = "0.8.14", optional = true } +zip = { version = "2.1.3", optional = true } -# chrono-lc breaks because of https://github.com/chronotope/chrono/compare/v0.4.34...v0.4.35#diff-67de5678fb5c14378bbff7ecf7f8bfab17cc223c4726f8da3afca183a4e59543 -chrono = { version = "=0.4.34", features = ["serde"] } - -clap = { version = "4.5.3", features = ["derive"], optional = true } +anyhow = { version = "1.0.86", optional = true } +open = { version = "5.3.0", optional = true } +keyring = { version = "3.0.1", features = ["crypto-rust", "windows-native", "apple-native", "linux-native"], optional = true } +colored = { version = "2.1.0", optional = true } +nondestructive = { version = "0.0.25", optional = true } +clap = { version = "4.5.9", features = ["derive"], optional = true } directories = { version = "5.0.1", optional = true } -keyring = { version = "2.3.2", optional = true } -anyhow = { version = "1.0.81", optional = true } ignore = { version = "0.4.22", optional = true } pretty_env_logger = { version = "0.5.0", optional = true } -lune = { version = "0.8.2", optional = true } -futures-executor = { version = "0.3.30", optional = true } indicatif = { version = "0.17.8", optional = true } -auth-git2 = { version = "0.5.4", optional = true } indicatif-log-bridge = { version = "0.2.2", optional = true } -inquire = { version = "0.7.3", optional = true } -once_cell = { version = "1.19.0", optional = true } - -[dev-dependencies] -tempfile = "3.10.1" +inquire = { version = "0.7.5", optional = true } [workspace] resolver = "2" -members = [ - "registry" -] +members = [] [profile.dev.package.full_moon] -opt-level = 3 \ No newline at end of file +opt-level = 3 diff --git a/README.md b/README.md index a4e0277..8b0d32d 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@
+# Important + +> pesde is currently being rewritten, and this new version is not yet ready for use. You can find the stable version in the `master` branch. + pesde is a package manager for Roblox that is designed to be feature-rich and easy to use. Currently, pesde is in a very early stage of development, but already supports the following features: @@ -17,7 +21,8 @@ Currently, pesde is in a very early stage of development, but already supports t ## Installation -pesde can be installed from GitHub Releases. You can find the latest release [here](https://github.com/daimond113/pesde/releases). +pesde can be installed from GitHub Releases. You can find the latest +release [here](https://github.com/daimond113/pesde/releases). It can also be installed by using [Aftman](https://github.com/LPGhatguy/aftman). ## Usage @@ -52,13 +57,16 @@ pesde run daimond113/pesde -- --help ## Preparing to publish -To publish you must first initialize a new project with `pesde init`. You can then use the other commands to manipulate dependencies, and edit the file +To publish you must first initialize a new project with `pesde init`. You can then use the other commands to manipulate +dependencies, and edit the file manually to add metadata such as authors, description, and license. > **Warning** -> The pesde CLI respects the `.gitignore` file and will not include files that are ignored. The `.pesdeignore` file has more power over the `.gitignore` file, so you can unignore files by prepending a `!` to the pattern. +> The pesde CLI respects the `.gitignore` file and will not include files that are ignored. The `.pesdeignore` file has +> more power over the `.gitignore` file, so you can unignore files by prepending a `!` to the pattern. -The pesde CLI supports the `.pesdeignore` file, which is similar to `.gitignore`. It can be used to include or exclude files from the package. +The pesde CLI supports the `.pesdeignore` file, which is similar to `.gitignore`. It can be used to include or exclude +files from the package. ## Documentation @@ -70,9 +78,11 @@ The main pesde registry is hosted on [fly.io](https://fly.io). You can find it a ### Self-hosting -You can self-host the registry by using the default implementation in the `registry` folder, or by creating your own implementation. The API +You can self-host the registry by using the default implementation in the `registry` folder, or by creating your own +implementation. The API must be compatible with the default implementation, which can be found in the `main.rs` file. ## Previous art -pesde is heavily inspired by [npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/), [Wally](https://wally.run), and [Cargo](https://doc.rust-lang.org/cargo/). +pesde is heavily inspired by [npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/), [Wally](https://wally.run), +and [Cargo](https://doc.rust-lang.org/cargo/). diff --git a/registry/.env.example b/registry/.env.example deleted file mode 100644 index 778c2a2..0000000 --- a/registry/.env.example +++ /dev/null @@ -1,11 +0,0 @@ -INDEX_REPO_URL=# url of the git repository to be used as the package index -S3_ENDPOINT=# endpoint of the s3 bucket -S3_BUCKET_NAME=# name of the s3 bucket -S3_REGION=# region of the s3 bucket -S3_ACCESS_KEY=# access key of the s3 bucket -S3_SECRET_KEY=# secret key of the s3 bucket -COMMITTER_GIT_NAME=# name of the committer used for index updates -COMMITTER_GIT_EMAIL=# email of the committer used for index updates -GITHUB_USERNAME=# username of github account with push access to the index repository -GITHUB_PAT=# personal access token of github account with push access to the index repository -SENTRY_URL=# optional url of sentry error tracking \ No newline at end of file diff --git a/registry/Cargo.toml b/registry/Cargo.toml deleted file mode 100644 index 4d68c15..0000000 --- a/registry/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "pesde-registry" -version = "0.6.1" -edition = "2021" - -[dependencies] -actix-web = "4.5.1" -actix-cors = "0.7.0" -actix-web-httpauth = "0.8.1" -actix-multipart = "0.6.1" -actix-multipart-derive = "0.6.1" -actix-governor = "0.5.0" -dotenvy = "0.15.7" -reqwest = { version = "0.12.1", features = ["json", "blocking"] } -rusty-s3 = "0.5.0" -serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.114" -serde_yaml = "0.9.33" -flate2 = "1.0.28" -tar = "0.4.40" -pesde = { path = ".." } -semver = "1.0.22" -git2 = "0.18.3" -thiserror = "1.0.58" -tantivy = "0.21.1" -log = "0.4.21" -pretty_env_logger = "0.5.0" -sentry = "0.32.2" -sentry-log = "0.32.2" -sentry-actix = "0.32.2" - -# zstd-sys v2.0.10 is broken: https://github.com/gyscos/zstd-rs/issues/268 -zstd-sys = "=2.0.9" \ No newline at end of file diff --git a/registry/src/endpoints/mod.rs b/registry/src/endpoints/mod.rs deleted file mode 100644 index 503723f..0000000 --- a/registry/src/endpoints/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod packages; -pub mod search; diff --git a/registry/src/endpoints/packages.rs b/registry/src/endpoints/packages.rs deleted file mode 100644 index 6d9d9a4..0000000 --- a/registry/src/endpoints/packages.rs +++ /dev/null @@ -1,256 +0,0 @@ -use actix_multipart::form::{bytes::Bytes, MultipartForm}; -use actix_web::{web, HttpResponse, Responder}; -use flate2::read::GzDecoder; -use log::error; -use reqwest::StatusCode; -use rusty_s3::S3Action; -use tantivy::{doc, DateTime, Term}; -use tar::Archive; - -use pesde::{ - dependencies::DependencySpecifier, index::Index, manifest::Manifest, - package_name::StandardPackageName, project::DEFAULT_INDEX_NAME, IGNORED_FOLDERS, - MANIFEST_FILE_NAME, -}; - -use crate::{commit_signature, errors, AppState, UserId, S3_EXPIRY}; - -#[derive(MultipartForm)] -pub struct CreateForm { - #[multipart(limit = "4 MiB")] - tarball: Bytes, -} - -pub async fn create_package( - form: MultipartForm, - app_state: web::Data, - user_id: web::ReqData, -) -> Result { - let bytes = form.tarball.data.as_ref().to_vec(); - let mut decoder = GzDecoder::new(bytes.as_slice()); - let mut archive = Archive::new(&mut decoder); - - let archive_entries = archive.entries()?.filter_map(|e| e.ok()); - - let mut manifest = None; - - for mut e in archive_entries { - let Ok(path) = e.path() else { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: "Attached file contains non-UTF-8 path".to_string(), - })); - }; - - let Some(path) = path.as_os_str().to_str() else { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: "Attached file contains non-UTF-8 path".to_string(), - })); - }; - - match path { - MANIFEST_FILE_NAME => { - if !e.header().entry_type().is_file() { - continue; - } - - let received_manifest: Manifest = - serde_yaml::from_reader(&mut e).map_err(errors::Errors::UserYaml)?; - - manifest = Some(received_manifest); - } - path => { - if e.header().entry_type().is_file() { - continue; - } - - if IGNORED_FOLDERS.contains(&path) { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: format!("Attached file contains forbidden directory {}", path), - })); - } - } - } - } - - let Some(manifest) = manifest else { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: format!("Attached file doesn't contain {MANIFEST_FILE_NAME}"), - })); - }; - - let (scope, name) = manifest.name.parts(); - - let entry = { - let mut index = app_state.index.lock().unwrap(); - let config = index.config()?; - - for (dependency, _) in manifest.dependencies().into_values() { - match dependency { - DependencySpecifier::Git(_) => { - if !config.git_allowed { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: "Git dependencies are not allowed on this registry".to_string(), - })); - } - } - DependencySpecifier::Registry(registry) => { - if index - .package(®istry.name.clone().into()) - .unwrap() - .is_none() - { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: format!("Dependency {} not found", registry.name), - })); - } - - if registry.index != DEFAULT_INDEX_NAME && !config.custom_registry_allowed { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: "Custom registries are not allowed on this registry".to_string(), - })); - } - } - #[allow(unreachable_patterns)] - _ => {} - }; - } - - match index.create_package_version(&manifest, &user_id.0)? { - Some(entry) => { - index.commit_and_push( - &format!("Add version {}@{}", manifest.name, manifest.version), - &commit_signature(), - )?; - - entry - } - None => { - return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { - error: format!( - "Version {} of {} already exists", - manifest.version, manifest.name - ), - })); - } - } - }; - - { - let mut search_writer = app_state.search_writer.lock().unwrap(); - let schema = search_writer.index().schema(); - let name_field = schema.get_field("name").unwrap(); - - search_writer.delete_term(Term::from_field_text( - name_field, - &manifest.name.to_string(), - )); - - search_writer.add_document( - doc!( - name_field => manifest.name.to_string(), - schema.get_field("version").unwrap() => manifest.version.to_string(), - schema.get_field("description").unwrap() => manifest.description.unwrap_or_default(), - schema.get_field("published_at").unwrap() => DateTime::from_timestamp_secs(entry.published_at.timestamp()) - ) - ).unwrap(); - - search_writer.commit().unwrap(); - } - - let url = app_state - .s3_bucket - .put_object( - Some(&app_state.s3_credentials), - &format!("{scope}-{name}-{}.tar.gz", manifest.version), - ) - .sign(S3_EXPIRY); - - app_state.reqwest_client.put(url).body(bytes).send().await?; - - Ok(HttpResponse::Ok().body(format!( - "Successfully published {}@{}", - manifest.name, manifest.version - ))) -} - -pub async fn get_package_version( - app_state: web::Data, - path: web::Path<(String, String, String)>, -) -> Result { - let (scope, name, mut version) = path.into_inner(); - - let package_name = StandardPackageName::new(&scope, &name)?; - - { - let index = app_state.index.lock().unwrap(); - - match index.package(&package_name.clone().into())? { - Some(package) => { - if version == "latest" { - version = package.last().map(|v| v.version.to_string()).unwrap(); - } else if !package.iter().any(|v| v.version.to_string() == version) { - return Ok(HttpResponse::NotFound().finish()); - } - } - None => return Ok(HttpResponse::NotFound().finish()), - } - } - - let url = app_state - .s3_bucket - .get_object( - Some(&app_state.s3_credentials), - &format!("{scope}-{name}-{version}.tar.gz"), - ) - .sign(S3_EXPIRY); - - let response = match app_state - .reqwest_client - .get(url) - .send() - .await? - .error_for_status() - { - Ok(response) => response, - Err(e) => { - if let Some(status) = e.status() { - if status == StatusCode::NOT_FOUND { - error!( - "package {}@{} not found in S3, but found in index", - package_name, version - ); - return Ok(HttpResponse::InternalServerError().finish()); - } - } - - return Err(e.into()); - } - }; - - Ok(HttpResponse::Ok().body(response.bytes().await?)) -} - -pub async fn get_package_versions( - app_state: web::Data, - path: web::Path<(String, String)>, -) -> Result { - let (scope, name) = path.into_inner(); - - let package_name = StandardPackageName::new(&scope, &name)?; - - { - let index = app_state.index.lock().unwrap(); - - match index.package(&package_name.into())? { - Some(package) => { - let versions = package - .iter() - .map(|v| (v.version.to_string(), v.published_at.timestamp())) - .collect::>(); - - Ok(HttpResponse::Ok().json(versions)) - } - None => Ok(HttpResponse::NotFound().finish()), - } - } -} diff --git a/registry/src/endpoints/search.rs b/registry/src/endpoints/search.rs deleted file mode 100644 index 7fcff38..0000000 --- a/registry/src/endpoints/search.rs +++ /dev/null @@ -1,81 +0,0 @@ -use actix_web::{web, Responder}; -use semver::Version; -use serde::Deserialize; -use serde_json::{json, Value}; -use tantivy::{query::AllQuery, DateTime, DocAddress, Order}; - -use pesde::{index::Index, package_name::StandardPackageName}; - -use crate::{errors, AppState}; - -#[derive(Deserialize)] -pub struct Query { - query: Option, -} - -pub async fn search_packages( - app_state: web::Data, - query: web::Query, -) -> Result { - let searcher = app_state.search_reader.searcher(); - let schema = searcher.schema(); - - let name = schema.get_field("name").unwrap(); - let version = schema.get_field("version").unwrap(); - let description = schema.get_field("description").unwrap(); - - let query = query.query.as_deref().unwrap_or_default().trim(); - - let query_parser = - tantivy::query::QueryParser::for_index(searcher.index(), vec![name, description]); - let query = if query.is_empty() { - Box::new(AllQuery) - } else { - query_parser.parse_query(query)? - }; - - let top_docs: Vec<(DateTime, DocAddress)> = searcher - .search( - &query, - &tantivy::collector::TopDocs::with_limit(10) - .order_by_fast_field("published_at", Order::Desc), - ) - .unwrap(); - - { - let index = app_state.index.lock().unwrap(); - - Ok(web::Json( - top_docs - .into_iter() - .map(|(published_at, doc_address)| { - let retrieved_doc = searcher.doc(doc_address).unwrap(); - let name: StandardPackageName = retrieved_doc - .get_first(name) - .and_then(|v| v.as_text()) - .and_then(|v| v.parse().ok()) - .unwrap(); - - let version: Version = retrieved_doc - .get_first(version) - .and_then(|v| v.as_text()) - .and_then(|v| v.parse().ok()) - .unwrap(); - - let entry = index - .package(&name.clone().into()) - .unwrap() - .and_then(|v| v.into_iter().find(|v| v.version == version)) - .unwrap(); - - json!({ - "name": name, - "version": version, - "description": entry.description, - "published_at": published_at.into_timestamp_secs(), - }) - }) - .collect::>(), - )) - } -} diff --git a/registry/src/errors.rs b/registry/src/errors.rs deleted file mode 100644 index 712681f..0000000 --- a/registry/src/errors.rs +++ /dev/null @@ -1,77 +0,0 @@ -use actix_web::{HttpResponse, ResponseError}; -use log::error; -use pesde::index::CreatePackageVersionError; -use serde::Serialize; -use thiserror::Error; - -#[derive(Serialize)] -pub struct ErrorResponse { - pub error: String, -} - -#[derive(Debug, Error)] -pub enum Errors { - #[error("io error")] - Io(#[from] std::io::Error), - - #[error("user yaml error")] - UserYaml(serde_yaml::Error), - - #[error("reqwest error")] - Reqwest(#[from] reqwest::Error), - - #[error("package name invalid")] - PackageName(#[from] pesde::package_name::StandardPackageNameValidationError), - - #[error("config error")] - Config(#[from] pesde::index::ConfigError), - - #[error("create package version error")] - CreatePackageVersion(#[from] CreatePackageVersionError), - - #[error("commit and push error")] - CommitAndPush(#[from] pesde::index::CommitAndPushError), - - #[error("index package error")] - IndexPackage(#[from] pesde::index::IndexPackageError), - - #[error("error parsing query")] - QueryParser(#[from] tantivy::query::QueryParserError), -} - -impl ResponseError for Errors { - fn error_response(&self) -> HttpResponse { - match self { - Errors::UserYaml(_) | Errors::PackageName(_) | Errors::QueryParser(_) => {} - Errors::CreatePackageVersion(err) => match err { - CreatePackageVersionError::MissingScopeOwnership => { - return HttpResponse::Unauthorized().json(ErrorResponse { - error: "You do not have permission to publish this scope".to_string(), - }); - } - CreatePackageVersionError::FromManifestIndexFileEntry(err) => { - return HttpResponse::BadRequest().json(ErrorResponse { - error: format!("Error in manifest: {err:?}"), - }); - } - _ => error!("{err:?}"), - }, - err => { - error!("{err:?}"); - } - } - - match self { - Errors::UserYaml(err) => HttpResponse::BadRequest().json(ErrorResponse { - error: format!("Error parsing YAML file: {err}"), - }), - Errors::PackageName(err) => HttpResponse::BadRequest().json(ErrorResponse { - error: format!("Invalid package name: {err}"), - }), - Errors::QueryParser(err) => HttpResponse::BadRequest().json(ErrorResponse { - error: format!("Error parsing query: {err}"), - }), - _ => HttpResponse::InternalServerError().finish(), - } - } -} diff --git a/registry/src/main.rs b/registry/src/main.rs deleted file mode 100644 index e2b3da2..0000000 --- a/registry/src/main.rs +++ /dev/null @@ -1,316 +0,0 @@ -use std::{fs::read_dir, sync::Mutex, time::Duration}; - -use actix_cors::Cors; -use actix_governor::{Governor, GovernorConfigBuilder, KeyExtractor, SimpleKeyExtractionError}; -use actix_web::{ - dev::ServiceRequest, - error::ErrorUnauthorized, - middleware::{Compress, Condition, Logger}, - rt::System, - web, App, Error, HttpMessage, HttpServer, -}; -use actix_web_httpauth::{extractors::bearer::BearerAuth, middleware::HttpAuthentication}; -use dotenvy::dotenv; -use git2::{Cred, Signature}; -use log::info; -use reqwest::{header::AUTHORIZATION, Client}; -use rusty_s3::{Bucket, Credentials, UrlStyle}; -use tantivy::{doc, DateTime, IndexReader, IndexWriter}; - -use pesde::{ - index::{GitIndex, Index, IndexFile}, - package_name::StandardPackageName, -}; - -mod endpoints; -mod errors; - -const S3_EXPIRY: Duration = Duration::from_secs(60 * 60); - -struct AppState { - s3_bucket: Bucket, - s3_credentials: Credentials, - reqwest_client: Client, - index: Mutex, - - search_reader: IndexReader, - search_writer: Mutex, -} - -macro_rules! get_env { - ($name:expr, "p") => { - std::env::var($name) - .expect(concat!("Environment variable `", $name, "` must be set")) - .parse() - .expect(concat!( - "Environment variable `", - $name, - "` must be a valid value" - )) - }; - ($name:expr) => { - std::env::var($name).expect(concat!("Environment variable `", $name, "` must be set")) - }; - ($name:expr, $default:expr, "p") => { - std::env::var($name) - .unwrap_or($default.to_string()) - .parse() - .expect(concat!( - "Environment variable `", - $name, - "` must a valid value" - )) - }; - ($name:expr, $default:expr) => { - std::env::var($name).unwrap_or($default.to_string()) - }; -} - -pub fn commit_signature<'a>() -> Signature<'a> { - Signature::now( - &get_env!("COMMITTER_GIT_NAME"), - &get_env!("COMMITTER_GIT_EMAIL"), - ) - .unwrap() -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub struct UserId(pub u64); - -async fn validator( - req: ServiceRequest, - credentials: BearerAuth, -) -> Result { - let token = credentials.token(); - let app_state = req.app_data::>().unwrap(); - - let Ok(user_info) = app_state - .reqwest_client - .get("https://api.github.com/user") - .header(AUTHORIZATION, format!("Bearer {}", token)) - .send() - .await - .map(|r| r.json::()) - else { - return Err((ErrorUnauthorized("Failed to fetch user info"), req)); - }; - - let Ok(user_info) = user_info.await else { - return Err((ErrorUnauthorized("Failed to parse user info"), req)); - }; - - let Some(id) = user_info["id"].as_u64() else { - return Err((ErrorUnauthorized("Failed to fetch user info"), req)); - }; - - req.extensions_mut().insert(UserId(id)); - - Ok(req) -} - -#[derive(Debug, Clone)] -struct UserIdKey; - -impl KeyExtractor for UserIdKey { - type Key = UserId; - type KeyExtractionError = SimpleKeyExtractionError<&'static str>; - - fn extract(&self, req: &ServiceRequest) -> Result { - Ok(*req.extensions().get::().unwrap()) - } -} - -fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) { - let mut schema_builder = tantivy::schema::SchemaBuilder::new(); - let name = - schema_builder.add_text_field("name", tantivy::schema::TEXT | tantivy::schema::STORED); - let version = - schema_builder.add_text_field("version", tantivy::schema::TEXT | tantivy::schema::STORED); - let description = schema_builder.add_text_field("description", tantivy::schema::TEXT); - let published_at = schema_builder.add_date_field("published_at", tantivy::schema::FAST); - - let search_index = tantivy::Index::create_in_ram(schema_builder.build()); - let search_reader = search_index - .reader_builder() - .reload_policy(tantivy::ReloadPolicy::OnCommit) - .try_into() - .unwrap(); - let mut search_writer = search_index.writer(50_000_000).unwrap(); - - for entry in read_dir(index.path()).unwrap() { - let entry = entry.unwrap(); - let path = entry.path(); - - if !path.is_dir() || path.file_name().is_some_and(|v| v == ".git") { - continue; - } - - let scope = path.file_name().and_then(|v| v.to_str()).unwrap(); - - for entry in read_dir(&path).unwrap() { - let entry = entry.unwrap(); - let path = entry.path(); - - if !path.is_file() || path.extension().is_some() { - continue; - } - - let package = path.file_name().and_then(|v| v.to_str()).unwrap(); - - let package_name = StandardPackageName::new(scope, package).unwrap(); - let entries: IndexFile = - serde_yaml::from_slice(&std::fs::read(&path).unwrap()).unwrap(); - let entry = entries.last().unwrap().clone(); - - search_writer - .add_document(doc!( - name => package_name.to_string(), - version => entry.version.to_string(), - description => entry.description.unwrap_or_default(), - published_at => DateTime::from_timestamp_secs(entry.published_at.timestamp()), - )) - .unwrap(); - } - } - - search_writer.commit().unwrap(); - - (search_reader, search_writer) -} - -fn main() -> std::io::Result<()> { - dotenv().ok(); - - let sentry_url = std::env::var("SENTRY_URL").ok(); - let with_sentry = sentry_url.is_some(); - - let mut log_builder = pretty_env_logger::formatted_builder(); - log_builder.parse_env(pretty_env_logger::env_logger::Env::default().default_filter_or("info")); - - if with_sentry { - let logger = sentry_log::SentryLogger::with_dest(log_builder.build()); - log::set_boxed_logger(Box::new(logger)).unwrap(); - log::set_max_level(log::LevelFilter::Info); - } else { - log_builder.try_init().unwrap(); - } - - let _guard = if let Some(sentry_url) = sentry_url { - std::env::set_var("RUST_BACKTRACE", "1"); - - Some(sentry::init(( - sentry_url, - sentry::ClientOptions { - release: sentry::release_name!(), - ..Default::default() - }, - ))) - } else { - None - }; - - let address = get_env!("ADDRESS", "127.0.0.1"); - let port: u16 = get_env!("PORT", "8080", "p"); - - let current_dir = std::env::current_dir().unwrap(); - - let index = GitIndex::new( - current_dir.join("cache"), - &get_env!("INDEX_REPO_URL", "p"), - Some(Box::new(|| { - Box::new(|_, _, _| { - let username = get_env!("GITHUB_USERNAME"); - let pat = get_env!("GITHUB_PAT"); - - Cred::userpass_plaintext(&username, &pat) - }) - })), - None, - ); - index.refresh().expect("failed to refresh index"); - - let (search_reader, search_writer) = search_index(&index); - - let app_data = web::Data::new(AppState { - s3_bucket: Bucket::new( - get_env!("S3_ENDPOINT", "p"), - UrlStyle::Path, - get_env!("S3_BUCKET_NAME"), - get_env!("S3_REGION"), - ) - .unwrap(), - s3_credentials: Credentials::new(get_env!("S3_ACCESS_KEY"), get_env!("S3_SECRET_KEY")), - reqwest_client: Client::builder() - .user_agent(concat!( - env!("CARGO_PKG_NAME"), - "/", - env!("CARGO_PKG_VERSION") - )) - .build() - .unwrap(), - index: Mutex::new(index), - - search_reader, - search_writer: Mutex::new(search_writer), - }); - - let upload_governor_config = GovernorConfigBuilder::default() - .burst_size(10) - .per_second(600) - .key_extractor(UserIdKey) - .use_headers() - .finish() - .unwrap(); - - let generic_governor_config = GovernorConfigBuilder::default() - .burst_size(50) - .per_second(10) - .use_headers() - .finish() - .unwrap(); - - info!("listening on {address}:{port}"); - - System::new().block_on(async move { - HttpServer::new(move || { - App::new() - .wrap(Condition::new(with_sentry, sentry_actix::Sentry::new())) - .wrap(Logger::default()) - .wrap(Cors::permissive()) - .wrap(Compress::default()) - .app_data(app_data.clone()) - .route("/", web::get().to(|| async { env!("CARGO_PKG_VERSION") })) - .service( - web::scope("/v0") - .route( - "/search", - web::get() - .to(endpoints::search::search_packages) - .wrap(Governor::new(&generic_governor_config)), - ) - .route( - "/packages/{scope}/{name}/versions", - web::get() - .to(endpoints::packages::get_package_versions) - .wrap(Governor::new(&generic_governor_config)), - ) - .route( - "/packages/{scope}/{name}/{version}", - web::get() - .to(endpoints::packages::get_package_version) - .wrap(Governor::new(&generic_governor_config)), - ) - .route( - "/packages", - web::post() - .to(endpoints::packages::create_package) - .wrap(Governor::new(&upload_governor_config)) - .wrap(HttpAuthentication::bearer(validator)), - ), - ) - }) - .bind((address, port))? - .run() - .await - }) -} diff --git a/src/cli/api_token.rs b/src/cli/api_token.rs deleted file mode 100644 index 952e241..0000000 --- a/src/cli/api_token.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::path::PathBuf; - -use crate::cli::DEFAULT_INDEX_DATA; -use keyring::Entry; -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; - -struct EnvVarApiTokenSource; - -const API_TOKEN_ENV_VAR: &str = "PESDE_API_TOKEN"; - -impl EnvVarApiTokenSource { - fn get_api_token(&self) -> anyhow::Result> { - match std::env::var(API_TOKEN_ENV_VAR) { - Ok(token) => Ok(Some(token)), - Err(std::env::VarError::NotPresent) => Ok(None), - Err(e) => Err(e.into()), - } - } -} - -static AUTH_FILE_PATH: Lazy = - Lazy::new(|| DEFAULT_INDEX_DATA.0.parent().unwrap().join("auth.yaml")); -static AUTH_FILE: Lazy = - Lazy::new( - || match std::fs::read_to_string(AUTH_FILE_PATH.to_path_buf()) { - Ok(config) => serde_yaml::from_str(&config).unwrap(), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => AuthFile::default(), - Err(e) => panic!("{:?}", e), - }, - ); - -#[derive(Serialize, Deserialize, Default, Clone)] -struct AuthFile { - #[serde(default)] - api_token: Option, -} - -struct ConfigFileApiTokenSource; - -impl ConfigFileApiTokenSource { - fn get_api_token(&self) -> anyhow::Result> { - Ok(AUTH_FILE.api_token.clone()) - } - - fn set_api_token(&self, api_token: &str) -> anyhow::Result<()> { - let mut config = AUTH_FILE.clone(); - config.api_token = Some(api_token.to_string()); - - serde_yaml::to_writer( - &mut std::fs::File::create(AUTH_FILE_PATH.to_path_buf())?, - &config, - )?; - - Ok(()) - } - - fn delete_api_token(&self) -> anyhow::Result<()> { - let mut config = AUTH_FILE.clone(); - - config.api_token = None; - - serde_yaml::to_writer( - &mut std::fs::File::create(AUTH_FILE_PATH.to_path_buf())?, - &config, - )?; - - Ok(()) - } -} - -static KEYRING_ENTRY: Lazy = - Lazy::new(|| Entry::new(env!("CARGO_PKG_NAME"), "api_token").unwrap()); - -struct KeyringApiTokenSource; - -impl KeyringApiTokenSource { - fn get_api_token(&self) -> anyhow::Result> { - match KEYRING_ENTRY.get_password() { - Ok(api_token) => Ok(Some(api_token)), - Err(err) => match err { - keyring::Error::NoEntry | keyring::Error::PlatformFailure(_) => Ok(None), - _ => Err(err.into()), - }, - } - } - - fn set_api_token(&self, api_token: &str) -> anyhow::Result<()> { - KEYRING_ENTRY.set_password(api_token)?; - - Ok(()) - } - - fn delete_api_token(&self) -> anyhow::Result<()> { - KEYRING_ENTRY.delete_password()?; - - Ok(()) - } -} - -#[derive(Debug)] -pub enum ApiTokenSource { - EnvVar, - ConfigFile, - Keyring, -} - -impl ApiTokenSource { - pub fn get_api_token(&self) -> anyhow::Result> { - match self { - ApiTokenSource::EnvVar => EnvVarApiTokenSource.get_api_token(), - ApiTokenSource::ConfigFile => ConfigFileApiTokenSource.get_api_token(), - ApiTokenSource::Keyring => KeyringApiTokenSource.get_api_token(), - } - } - - pub fn set_api_token(&self, api_token: &str) -> anyhow::Result<()> { - match self { - ApiTokenSource::EnvVar => Ok(()), - ApiTokenSource::ConfigFile => ConfigFileApiTokenSource.set_api_token(api_token), - ApiTokenSource::Keyring => KeyringApiTokenSource.set_api_token(api_token), - } - } - - pub fn delete_api_token(&self) -> anyhow::Result<()> { - match self { - ApiTokenSource::EnvVar => Ok(()), - ApiTokenSource::ConfigFile => ConfigFileApiTokenSource.delete_api_token(), - ApiTokenSource::Keyring => KeyringApiTokenSource.delete_api_token(), - } - } - - fn persists(&self) -> bool { - !matches!(self, ApiTokenSource::EnvVar) - } -} - -pub static API_TOKEN_SOURCE: Lazy = Lazy::new(|| { - let sources: [ApiTokenSource; 3] = [ - ApiTokenSource::EnvVar, - ApiTokenSource::ConfigFile, - ApiTokenSource::Keyring, - ]; - - let mut valid_sources = vec![]; - - for source in sources { - match source.get_api_token() { - Ok(Some(_)) => return source, - Ok(None) => { - if source.persists() { - valid_sources.push(source); - } - } - Err(e) => { - log::error!("error getting api token: {e}"); - } - } - } - - valid_sources.pop().unwrap() -}); diff --git a/src/cli/auth.rs b/src/cli/auth.rs deleted file mode 100644 index 87725a7..0000000 --- a/src/cli/auth.rs +++ /dev/null @@ -1,111 +0,0 @@ -use clap::Subcommand; -use pesde::index::Index; -use reqwest::{header::AUTHORIZATION, Url}; - -use crate::cli::{api_token::API_TOKEN_SOURCE, send_request, DEFAULT_INDEX, REQWEST_CLIENT}; - -#[derive(Subcommand, Clone)] -pub enum AuthCommand { - /// Logs in to the registry - Login, - /// Logs out from the registry - Logout, -} - -pub fn auth_command(cmd: AuthCommand) -> anyhow::Result<()> { - match cmd { - AuthCommand::Login => { - let github_oauth_client_id = DEFAULT_INDEX.config()?.github_oauth_client_id; - - let response = send_request(REQWEST_CLIENT.post(Url::parse_with_params( - "https://github.com/login/device/code", - &[("client_id", &github_oauth_client_id)], - )?))? - .json::()?; - - println!( - "go to {} and enter the code `{}`", - response["verification_uri"], response["user_code"] - ); - - let mut time_left = response["expires_in"] - .as_i64() - .ok_or(anyhow::anyhow!("couldn't get expires_in"))?; - let interval = std::time::Duration::from_secs( - response["interval"] - .as_u64() - .ok_or(anyhow::anyhow!("couldn't get interval"))?, - ); - let device_code = response["device_code"] - .as_str() - .ok_or(anyhow::anyhow!("couldn't get device_code"))?; - - while time_left > 0 { - std::thread::sleep(interval); - time_left -= interval.as_secs() as i64; - let response = send_request(REQWEST_CLIENT.post(Url::parse_with_params( - "https://github.com/login/oauth/access_token", - &[ - ("client_id", github_oauth_client_id.as_str()), - ("device_code", device_code), - ("grant_type", "urn:ietf:params:oauth:grant-type:device_code"), - ], - )?))? - .json::()?; - - match response - .get("error") - .map(|s| { - s.as_str() - .ok_or(anyhow::anyhow!("couldn't get error as string")) - }) - .unwrap_or(Ok(""))? - { - "authorization_pending" => continue, - "slow_down" => { - std::thread::sleep(std::time::Duration::from_secs(5)); - continue; - } - "expired_token" => { - break; - } - "access_denied" => { - anyhow::bail!("access denied, re-run the login command"); - } - _ => (), - } - - if response.get("access_token").is_some() { - let access_token = response["access_token"] - .as_str() - .ok_or(anyhow::anyhow!("couldn't get access_token"))?; - - API_TOKEN_SOURCE.set_api_token(access_token)?; - - let response = send_request( - REQWEST_CLIENT - .get("https://api.github.com/user") - .header(AUTHORIZATION, format!("Bearer {access_token}")), - )? - .json::()?; - - let login = response["login"] - .as_str() - .ok_or(anyhow::anyhow!("couldn't get login"))?; - - println!("you're now logged in as {login}"); - return Ok(()); - } - } - - anyhow::bail!("code expired, please re-run the login command"); - } - AuthCommand::Logout => { - API_TOKEN_SOURCE.delete_api_token()?; - - println!("you're now logged out"); - } - } - - Ok(()) -} diff --git a/src/cli/auth/login.rs b/src/cli/auth/login.rs new file mode 100644 index 0000000..f0dd9b4 --- /dev/null +++ b/src/cli/auth/login.rs @@ -0,0 +1,181 @@ +use crate::cli::{auth::get_token_login, read_config, reqwest_client, set_token}; +use anyhow::Context; +use clap::Args; +use colored::Colorize; +use pesde::{ + errors::ManifestReadError, + source::{pesde::PesdePackageSource, PackageSource}, + Project, +}; +use serde::Deserialize; +use url::Url; + +#[derive(Debug, Args)] +pub struct LoginCommand { + /// The index to use. Defaults to `default`, or the configured default index if current directory doesn't have a manifest + #[arg(short, long)] + index: Option, +} + +#[derive(Debug, Deserialize)] +struct DeviceCodeResponse { + device_code: String, + user_code: String, + verification_uri: Url, + expires_in: u64, + interval: u64, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "snake_case", tag = "error")] +enum AccessTokenError { + AuthorizationPending, + SlowDown { interval: u64 }, + ExpiredToken, + AccessDenied, +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +enum AccessTokenResponse { + Success { access_token: String }, + + Error(AccessTokenError), +} + +impl LoginCommand { + pub fn run(self, project: Project) -> anyhow::Result<()> { + let manifest = match project.deser_manifest() { + Ok(manifest) => Some(manifest), + Err(e) => match e { + ManifestReadError::Io(e) if e.kind() == std::io::ErrorKind::NotFound => None, + e => return Err(e.into()), + }, + }; + + let index_url = match &self.index { + Some(index) => match index.parse() { + Ok(url) => Some(url), + Err(_) => None, + }, + None => match manifest { + Some(_) => None, + None => Some(read_config(project.data_dir())?.default_index), + }, + }; + + let index_url = match index_url { + Some(url) => url, + None => { + let index_name = self.index.as_deref().unwrap_or("default"); + + match manifest.unwrap().indices.get(index_name) { + Some(index) => index.clone(), + None => anyhow::bail!("Index {index_name} not found"), + } + } + }; + + let source = PesdePackageSource::new( + index_url + .as_str() + .try_into() + .context("cannot parse URL to git URL")?, + ); + source + .refresh(&project) + .context("failed to refresh index")?; + + dbg!(source.all_packages(&project).unwrap()); + + let config = source + .config(&project) + .context("failed to read index config")?; + let client_id = config.github_oauth_client_id; + + let reqwest = reqwest_client(project.data_dir())?; + let response = reqwest + .post(Url::parse_with_params( + "https://github.com/login/device/code", + &[("client_id", &client_id)], + )?) + .send() + .context("failed to send device code request")? + .json::() + .context("failed to parse device code response")?; + + println!( + "copy your one-time code: {}\npress enter to open {} in your browser...", + response.user_code.bold(), + response.verification_uri.as_str().blue() + ); + + { + let mut input = String::new(); + std::io::stdin() + .read_line(&mut input) + .context("failed to read input")?; + } + + match open::that(response.verification_uri.as_str()) { + Ok(_) => (), + Err(e) => { + eprintln!("failed to open browser: {e}"); + } + } + + let mut time_left = response.expires_in; + let mut interval = std::time::Duration::from_secs(response.interval); + + while time_left > 0 { + std::thread::sleep(interval); + time_left = time_left.saturating_sub(interval.as_secs()); + + let response = reqwest + .post(Url::parse_with_params( + "https://github.com/login/oauth/access_token", + &[ + ("client_id", &client_id), + ("device_code", &response.device_code), + ( + "grant_type", + &"urn:ietf:params:oauth:grant-type:device_code".to_string(), + ), + ], + )?) + .send() + .context("failed to send access token request")? + .json::() + .context("failed to parse access token response")?; + + match response { + AccessTokenResponse::Success { access_token } => { + set_token(project.data_dir(), Some(&access_token))?; + + println!( + "logged in as {}", + get_token_login(&reqwest, &access_token)?.bold() + ); + return Ok(()); + } + AccessTokenResponse::Error(e) => match e { + AccessTokenError::AuthorizationPending => continue, + AccessTokenError::SlowDown { + interval: new_interval, + } => { + interval = std::time::Duration::from_secs(new_interval); + continue; + } + AccessTokenError::ExpiredToken => { + break; + } + AccessTokenError::AccessDenied => { + anyhow::bail!("access denied, re-run the login command"); + } + }, + } + } + + anyhow::bail!("code expired, please re-run the login command"); + } +} diff --git a/src/cli/auth/logout.rs b/src/cli/auth/logout.rs new file mode 100644 index 0000000..a2a1727 --- /dev/null +++ b/src/cli/auth/logout.rs @@ -0,0 +1,16 @@ +use crate::cli::set_token; +use clap::Args; +use pesde::Project; + +#[derive(Debug, Args)] +pub struct LogoutCommand {} + +impl LogoutCommand { + pub fn run(self, project: Project) -> anyhow::Result<()> { + set_token(project.data_dir(), None)?; + + println!("logged out"); + + Ok(()) + } +} diff --git a/src/cli/auth/mod.rs b/src/cli/auth/mod.rs new file mode 100644 index 0000000..ad8f7f6 --- /dev/null +++ b/src/cli/auth/mod.rs @@ -0,0 +1,49 @@ +use anyhow::Context; +use clap::Subcommand; +use pesde::Project; +use serde::Deserialize; + +mod login; +mod logout; +mod whoami; + +#[derive(Debug, Deserialize)] +struct UserResponse { + login: String, +} + +pub fn get_token_login( + reqwest: &reqwest::blocking::Client, + access_token: &str, +) -> anyhow::Result { + let response = reqwest + .get("https://api.github.com/user") + .header("Authorization", format!("Bearer {access_token}")) + .send() + .context("failed to send user request")? + .json::() + .context("failed to parse user response")?; + + Ok(response.login) +} + +#[derive(Debug, Subcommand)] +pub enum AuthCommands { + /// Logs in into GitHub, and stores the token + Login(login::LoginCommand), + /// Removes the stored token + Logout(logout::LogoutCommand), + /// Prints the username of the currently logged-in user + #[clap(name = "whoami")] + WhoAmI(whoami::WhoAmICommand), +} + +impl AuthCommands { + pub fn run(self, project: Project) -> anyhow::Result<()> { + match self { + AuthCommands::Login(login) => login.run(project), + AuthCommands::Logout(logout) => logout.run(project), + AuthCommands::WhoAmI(whoami) => whoami.run(project), + } + } +} diff --git a/src/cli/auth/whoami.rs b/src/cli/auth/whoami.rs new file mode 100644 index 0000000..6a314ee --- /dev/null +++ b/src/cli/auth/whoami.rs @@ -0,0 +1,26 @@ +use crate::cli::{auth::get_token_login, get_token, reqwest_client}; +use clap::Args; +use colored::Colorize; +use pesde::Project; + +#[derive(Debug, Args)] +pub struct WhoAmICommand {} + +impl WhoAmICommand { + pub fn run(self, project: Project) -> anyhow::Result<()> { + let token = match get_token(project.data_dir())? { + Some(token) => token, + None => { + println!("not logged in"); + return Ok(()); + } + }; + + println!( + "logged in as {}", + get_token_login(&reqwest_client(project.data_dir())?, &token)?.bold() + ); + + Ok(()) + } +} diff --git a/src/cli/config.rs b/src/cli/config.rs deleted file mode 100644 index cddecb1..0000000 --- a/src/cli/config.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::path::PathBuf; - -use clap::Subcommand; - -use crate::{cli::CLI_CONFIG, CliConfig}; - -#[derive(Subcommand, Clone)] -pub enum ConfigCommand { - /// Sets the cache directory - SetCacheDir { - /// The directory to use as the cache directory - #[clap(value_name = "DIRECTORY")] - directory: Option, - }, - /// Gets the cache directory - GetCacheDir, -} - -pub fn config_command(cmd: ConfigCommand) -> anyhow::Result<()> { - match cmd { - ConfigCommand::SetCacheDir { directory } => { - let cli_config = CliConfig { - cache_dir: directory, - }; - - cli_config.write()?; - - println!( - "cache directory set to: `{}`", - cli_config.cache_dir().display() - ); - } - ConfigCommand::GetCacheDir => { - println!( - "current cache directory: `{}`", - CLI_CONFIG.cache_dir().display() - ); - } - } - - Ok(()) -} diff --git a/src/cli/config/default_index.rs b/src/cli/config/default_index.rs new file mode 100644 index 0000000..63e78ad --- /dev/null +++ b/src/cli/config/default_index.rs @@ -0,0 +1,39 @@ +use crate::cli::{read_config, write_config, CliConfig}; +use clap::Args; +use pesde::Project; + +#[derive(Debug, Args)] +pub struct DefaultIndexCommand { + /// The new index URL to set as default, don't pass any value to check the current default index + #[arg(index = 1)] + index: Option, + + /// Resets the default index to the default value + #[arg(short, long, conflicts_with = "index")] + reset: bool, +} + +impl DefaultIndexCommand { + pub fn run(self, project: Project) -> anyhow::Result<()> { + let mut config = read_config(project.data_dir())?; + + let index = if self.reset { + Some(CliConfig::default().default_index) + } else { + self.index + }; + + match index { + Some(index) => { + config.default_index = index.clone(); + write_config(project.data_dir(), &config)?; + println!("default index set to: {}", index); + } + None => { + println!("current default index: {}", config.default_index); + } + } + + Ok(()) + } +} diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs new file mode 100644 index 0000000..ff7ff24 --- /dev/null +++ b/src/cli/config/mod.rs @@ -0,0 +1,18 @@ +use clap::Subcommand; +use pesde::Project; + +mod default_index; + +#[derive(Debug, Subcommand)] +pub enum ConfigCommands { + /// Configuration for the default index + DefaultIndex(default_index::DefaultIndexCommand), +} + +impl ConfigCommands { + pub fn run(self, project: Project) -> anyhow::Result<()> { + match self { + ConfigCommands::DefaultIndex(default_index) => default_index.run(project), + } + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index df1fafd..87eeb8f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,295 +1,145 @@ -use crate::cli::{api_token::API_TOKEN_SOURCE, auth::AuthCommand, config::ConfigCommand}; -use auth_git2::GitAuthenticator; -use clap::{Parser, Subcommand}; -use directories::ProjectDirs; -use indicatif::MultiProgress; -use indicatif_log_bridge::LogWrapper; -use log::error; -use once_cell::sync::Lazy; -use pesde::{ - index::{GitIndex, Index}, - manifest::{Manifest, Realm}, - package_name::{PackageName, StandardPackageName}, - project::DEFAULT_INDEX_NAME, -}; -use pretty_env_logger::env_logger::Env; -use reqwest::{ - blocking::{RequestBuilder, Response}, - header::ACCEPT, -}; -use semver::{Version, VersionReq}; +use clap::Subcommand; + +use anyhow::Context; +use keyring::Entry; +use pesde::Project; use serde::{Deserialize, Serialize}; -use std::{ - fs::create_dir_all, - hash::{DefaultHasher, Hash, Hasher}, - path::PathBuf, - str::FromStr, -}; +use std::path::Path; -pub mod api_token; -pub mod auth; -pub mod config; -pub mod root; +mod auth; +mod config; -#[derive(Debug, Clone)] -pub struct VersionedPackageName>(PackageName, V); - -impl> FromStr for VersionedPackageName { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let (name, version) = s.split_once('@').ok_or_else(|| { - anyhow::anyhow!("invalid package name: {s}; expected format: name@version") - })?; - - Ok(VersionedPackageName( - name.to_string().parse()?, - version.parse()?, - )) - } -} - -#[derive(Subcommand, Clone)] -pub enum Command { - /// Initializes a manifest file - Init, - - /// Adds a package to the manifest - Add { - /// The package to add - #[clap(value_name = "PACKAGE")] - package: VersionedPackageName, - - /// Whether the package is a peer dependency - #[clap(long, short)] - peer: bool, - - /// The realm of the package - #[clap(long, short)] - realm: Option, - }, - - /// Removes a package from the manifest - Remove { - /// The package to remove - #[clap(value_name = "PACKAGE")] - package: PackageName, - }, - - /// Lists outdated packages - Outdated, - - /// Installs the dependencies of the project - Install { - /// Whether to use the lockfile for resolving dependencies - #[clap(long, short)] - locked: bool, - }, - - /// Runs the `bin` export of the specified package - Run { - /// The package to run - #[clap(value_name = "PACKAGE")] - package: Option, - - /// The arguments to pass to the package - #[clap(last = true)] - args: Vec, - }, - - /// Searches for a package on the registry - Search { - /// The query to search for - #[clap(value_name = "QUERY")] - query: Option, - }, - - /// Publishes the project to the registry - Publish, - - /// Converts a `wally.toml` file to a `pesde.yaml` file - #[cfg(feature = "wally")] - Convert, - - /// Begins a new patch - Patch { - /// The package to patch - #[clap(value_name = "PACKAGE")] - package: VersionedPackageName, - }, - - /// Commits (finishes) the patch - PatchCommit { - /// The package's changed directory - #[clap(value_name = "DIRECTORY")] - dir: PathBuf, - }, - - /// Auth-related commands - Auth { - #[clap(subcommand)] - command: AuthCommand, - }, - - /// Config-related commands - Config { - #[clap(subcommand)] - command: ConfigCommand, - }, -} - -#[derive(Parser, Clone)] -#[clap(version = env!("CARGO_PKG_VERSION"))] -pub struct Cli { - #[clap(subcommand)] - pub command: Command, - - /// The directory to run the command in - #[arg(short, long, value_name = "DIRECTORY")] - pub directory: Option, -} - -#[derive(Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct CliConfig { - pub cache_dir: Option, + pub default_index: url::Url, + pub token: Option, } -impl CliConfig { - pub fn cache_dir(&self) -> PathBuf { - self.cache_dir - .clone() - .unwrap_or_else(|| DIRS.cache_dir().to_path_buf()) - } - - pub fn open() -> anyhow::Result { - let cli_config_path = DIRS.config_dir().join("config.yaml"); - - if cli_config_path.exists() { - Ok(serde_yaml::from_slice(&std::fs::read(cli_config_path)?)?) - } else { - let config = CliConfig::default(); - config.write()?; - Ok(config) - } - } - - pub fn write(&self) -> anyhow::Result<()> { - let folder = DIRS.config_dir(); - create_dir_all(folder)?; - serde_yaml::to_writer( - &mut std::fs::File::create(folder.join("config.yaml"))?, - &self, - )?; - - Ok(()) - } -} - -pub fn send_request(request_builder: RequestBuilder) -> anyhow::Result { - let res = request_builder.send()?; - - match res.error_for_status_ref() { - Ok(_) => Ok(res), - Err(e) => { - error!("request failed: {e}\nbody: {}", res.text()?); - Err(e.into()) +impl Default for CliConfig { + fn default() -> Self { + Self { + default_index: "https://github.com/daimond113/pesde-index".parse().unwrap(), + token: None, } } } -pub static CLI: Lazy = Lazy::new(Cli::parse); +pub fn read_config(data_dir: &Path) -> anyhow::Result { + let config_string = match std::fs::read_to_string(data_dir.join("config.yaml")) { + Ok(config_string) => config_string, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + return Ok(CliConfig::default()); + } + Err(e) => return Err(e).context("failed to read config file"), + }; -pub static DIRS: Lazy = Lazy::new(|| { - ProjectDirs::from("com", env!("CARGO_PKG_NAME"), env!("CARGO_BIN_NAME")) - .expect("couldn't get home directory") -}); + let config = serde_yaml::from_str(&config_string).context("failed to parse config file")?; -pub static CLI_CONFIG: Lazy = Lazy::new(|| CliConfig::open().unwrap()); + Ok(config) +} -pub static CWD: Lazy = Lazy::new(|| { - CLI.directory - .clone() - .or(std::env::current_dir().ok()) - .expect("couldn't get current directory") -}); +pub fn write_config(data_dir: &Path, config: &CliConfig) -> anyhow::Result<()> { + let config_string = serde_yaml::to_string(config).context("failed to serialize config")?; + std::fs::write(data_dir.join("config.yaml"), config_string) + .context("failed to write config file")?; -pub static REQWEST_CLIENT: Lazy = Lazy::new(|| { - let mut header_map = reqwest::header::HeaderMap::new(); - header_map.insert(ACCEPT, "application/json".parse().unwrap()); - header_map.insert("X-GitHub-Api-Version", "2022-11-28".parse().unwrap()); + Ok(()) +} - if let Ok(Some(token)) = API_TOKEN_SOURCE.get_api_token() { - header_map.insert( +pub fn get_token(data_dir: &Path) -> anyhow::Result> { + match std::env::var("PESDE_TOKEN") { + Ok(token) => return Ok(Some(token)), + Err(std::env::VarError::NotPresent) => {} + Err(e) => return Err(e.into()), + } + + let config = read_config(data_dir)?; + if let Some(token) = config.token { + return Ok(Some(token)); + } + + match Entry::new("token", env!("CARGO_PKG_NAME")) { + Ok(entry) => match entry.get_password() { + Ok(token) => return Ok(Some(token)), + Err(keyring::Error::PlatformFailure(_) | keyring::Error::NoEntry) => {} + Err(e) => return Err(e.into()), + }, + Err(keyring::Error::PlatformFailure(_)) => {} + Err(e) => return Err(e.into()), + } + + Ok(None) +} + +pub fn set_token(data_dir: &Path, token: Option<&str>) -> anyhow::Result<()> { + let entry = match Entry::new("token", env!("CARGO_PKG_NAME")) { + Ok(entry) => entry, + Err(e) => return Err(e.into()), + }; + + let result = if let Some(token) = token { + entry.set_password(token) + } else { + entry.delete_credential() + }; + + match result { + Ok(()) => return Ok(()), + Err(keyring::Error::PlatformFailure(_) | keyring::Error::NoEntry) => {} + Err(e) => return Err(e.into()), + } + + let mut config = read_config(data_dir)?; + config.token = token.map(|s| s.to_string()); + write_config(data_dir, &config)?; + + Ok(()) +} + +pub fn reqwest_client(data_dir: &Path) -> anyhow::Result { + let mut headers = reqwest::header::HeaderMap::new(); + if let Some(token) = get_token(data_dir)? { + headers.insert( reqwest::header::AUTHORIZATION, - format!("Bearer {token}").parse().unwrap(), + format!("Bearer {}", token) + .parse() + .context("failed to create auth header")?, ); } - reqwest::blocking::Client::builder() + headers.insert( + reqwest::header::ACCEPT, + "application/json" + .parse() + .context("failed to create accept header")?, + ); + + Ok(reqwest::blocking::Client::builder() .user_agent(concat!( env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION") )) - .default_headers(header_map) - .build() - .unwrap() -}); - -pub static MULTI: Lazy = Lazy::new(|| { - let logger = pretty_env_logger::formatted_builder() - .parse_env(Env::default().default_filter_or("info")) - .build(); - let multi = MultiProgress::new(); - - LogWrapper::new(multi.clone(), logger).try_init().unwrap(); - - multi -}); - -pub const DEFAULT_INDEX_URL: &str = "https://github.com/daimond113/pesde-index"; -#[cfg(feature = "wally")] -pub const DEFAULT_WALLY_INDEX_URL: &str = "https://github.com/UpliftGames/wally-index"; - -pub fn index_dir(url: &str) -> PathBuf { - let mut hasher = DefaultHasher::new(); - url.hash(&mut hasher); - let hash = hasher.finish().to_string(); - - CLI_CONFIG - .cache_dir() - .join("indices") - .join(hash) - .join("index") + .default_headers(headers) + .build()?) } -pub fn clone_index(url: &str) -> GitIndex { - let index = GitIndex::new( - index_dir(url), - &url.parse().unwrap(), - Some(Box::new(|| { - Box::new(|a, b, c| { - let git_authenticator = GitAuthenticator::new(); - let config = git2::Config::open_default().unwrap(); - let mut cred = git_authenticator.credentials(&config); +#[derive(Debug, Subcommand)] +pub enum SubCommand { + /// Authentication-related commands + #[command(subcommand)] + Auth(auth::AuthCommands), - cred(a, b, c) - }) - })), - API_TOKEN_SOURCE.get_api_token().unwrap(), - ); - - index.refresh().unwrap(); - - index + /// Configuration-related commands + #[command(subcommand)] + Config(config::ConfigCommands), } -pub static DEFAULT_INDEX_DATA: Lazy<(PathBuf, String)> = Lazy::new(|| { - let manifest = Manifest::from_path(CWD.to_path_buf()) - .map(|m| m.indices.get(DEFAULT_INDEX_NAME).unwrap().clone()); - let url = &manifest.unwrap_or(DEFAULT_INDEX_URL.to_string()); - - (index_dir(url), url.clone()) -}); - -pub static DEFAULT_INDEX: Lazy = Lazy::new(|| clone_index(&DEFAULT_INDEX_DATA.1)); +impl SubCommand { + pub fn run(self, project: Project) -> anyhow::Result<()> { + match self { + SubCommand::Auth(auth) => auth.run(project), + SubCommand::Config(config) => config.run(project), + } + } +} diff --git a/src/cli/root.rs b/src/cli/root.rs deleted file mode 100644 index 4bcb2dc..0000000 --- a/src/cli/root.rs +++ /dev/null @@ -1,593 +0,0 @@ -use cfg_if::cfg_if; -use chrono::Utc; -use std::{ - collections::{BTreeMap, HashMap}, - fs::{create_dir_all, read, remove_dir_all, write}, - str::FromStr, - time::Duration, -}; - -use flate2::{write::GzEncoder, Compression}; -use futures_executor::block_on; -use ignore::{overrides::OverrideBuilder, WalkBuilder}; -use inquire::{validator::Validation, Select, Text}; -use log::debug; -use lune::Runtime; -use once_cell::sync::Lazy; -use reqwest::{header::AUTHORIZATION, Url}; -use semver::Version; -use serde_json::Value; -use tar::Builder as TarBuilder; - -use pesde::{ - dependencies::{registry::RegistryDependencySpecifier, DependencySpecifier, PackageRef}, - index::Index, - manifest::{Manifest, PathStyle, Realm}, - multithread::MultithreadedJob, - package_name::{PackageName, StandardPackageName}, - patches::{create_patch, setup_patches_repo}, - project::{InstallOptions, Project, DEFAULT_INDEX_NAME}, - DEV_PACKAGES_FOLDER, IGNORED_FOLDERS, MANIFEST_FILE_NAME, PACKAGES_FOLDER, PATCHES_FOLDER, - SERVER_PACKAGES_FOLDER, -}; - -use crate::cli::{ - clone_index, send_request, Command, CLI_CONFIG, CWD, DEFAULT_INDEX, DEFAULT_INDEX_URL, DIRS, - MULTI, REQWEST_CLIENT, -}; - -pub const MAX_ARCHIVE_SIZE: usize = 4 * 1024 * 1024; - -fn multithreaded_bar + 'static>( - job: MultithreadedJob, - len: u64, - message: String, -) -> Result<(), anyhow::Error> { - let bar = MULTI.add( - indicatif::ProgressBar::new(len) - .with_style( - indicatif::ProgressStyle::default_bar() - .template("{msg} {bar:40.208/166} {pos}/{len} {percent}% {elapsed_precise}")?, - ) - .with_message(message), - ); - bar.enable_steady_tick(Duration::from_millis(100)); - - while let Ok(result) = job.progress().recv() { - result.map_err(Into::into)?; - bar.inc(1); - } - - bar.finish_with_message("done"); - - Ok(()) -} - -macro_rules! none_if_empty { - ($s:expr) => { - if $s.is_empty() { - None - } else { - Some($s) - } - }; -} - -pub fn root_command(cmd: Command) -> anyhow::Result<()> { - let mut project: Lazy = Lazy::new(|| { - let manifest = Manifest::from_path(CWD.to_path_buf()).unwrap(); - let indices = manifest - .indices - .clone() - .into_iter() - .map(|(k, v)| (k, Box::new(clone_index(&v)) as Box)) - .collect::>(); - - Project::new(CWD.to_path_buf(), CLI_CONFIG.cache_dir(), indices, manifest).unwrap() - }); - - match cmd { - Command::Install { locked } => { - for packages_folder in &[PACKAGES_FOLDER, DEV_PACKAGES_FOLDER, SERVER_PACKAGES_FOLDER] { - if let Err(e) = remove_dir_all(CWD.join(packages_folder)) { - if e.kind() != std::io::ErrorKind::NotFound { - return Err(e.into()); - } else { - debug!("no {packages_folder} folder found, skipping removal"); - } - }; - } - - let manifest = project.manifest().clone(); - let lockfile = manifest.dependency_graph(&mut project, locked)?; - - let download_job = project.download(&lockfile)?; - - multithreaded_bar( - download_job, - lockfile.children.values().map(|v| v.len() as u64).sum(), - "Downloading packages".to_string(), - )?; - - cfg_if! { - if #[cfg(feature = "wally")] { - let sourcemap_generator = manifest.sourcemap_generator.clone(); - } - } - - #[allow(unused_variables)] - let convert_job = project.convert_manifests(&lockfile, move |path| { - cfg_if! { - if #[cfg(feature = "wally")] { - if let Some(sourcemap_generator) = &sourcemap_generator { - cfg_if! { - if #[cfg(target_os = "windows")] { - std::process::Command::new("powershell") - .args(["-C", &sourcemap_generator]) - .current_dir(path) - .output() - .expect("failed to execute process"); - } else { - std::process::Command::new("sh") - .args(["-c", &sourcemap_generator]) - .current_dir(path) - .output() - .expect("failed to execute process"); - } - } - } - } - } - }); - - cfg_if! { - if #[cfg(feature = "wally")] { - multithreaded_bar( - convert_job, - lockfile.children.values().flat_map(|v| v.values()).filter(|v| matches!(v.pkg_ref, PackageRef::Git(_) | PackageRef::Wally(_))).count() as u64, - "Converting manifests".to_string(), - )?; - } else { - convert_job?; - } - } - - let project = Lazy::force_mut(&mut project); - - project.install( - InstallOptions::new() - .locked(locked) - .auto_download(false) - .lockfile(lockfile), - )?; - } - Command::Run { package, args } => { - let bin_path = if let Some(package) = package { - let lockfile = project - .lockfile()? - .ok_or(anyhow::anyhow!("lockfile not found"))?; - - let resolved_pkg = lockfile - .children - .get(&package.clone().into()) - .and_then(|versions| { - versions - .values() - .find(|pkg_ref| lockfile.root_specifier(pkg_ref).is_some()) - }) - .ok_or(anyhow::anyhow!( - "package not found in lockfile (or isn't root)" - ))?; - - let pkg_path = resolved_pkg.directory(project.path()).1; - let manifest = Manifest::from_path(&pkg_path)?; - - let Some(bin_path) = manifest.exports.bin else { - anyhow::bail!("no bin found in package"); - }; - - bin_path.to_path(pkg_path) - } else { - let manifest = project.manifest(); - let bin_path = manifest - .exports - .bin - .clone() - .ok_or(anyhow::anyhow!("no bin found in package"))?; - - bin_path.to_path(project.path()) - }; - - let mut runtime = Runtime::new().with_args(args); - - block_on(runtime.run( - bin_path.with_extension("").display().to_string(), - &read(bin_path)?, - ))?; - } - Command::Search { query } => { - let config = DEFAULT_INDEX.config()?; - let api_url = config.api(); - - let response = send_request(REQWEST_CLIENT.get(Url::parse_with_params( - &format!("{}/v0/search", api_url), - &query.map(|q| vec![("query", q)]).unwrap_or_default(), - )?))? - .json::()?; - - for package in response.as_array().unwrap() { - println!( - "{}@{}{}", - package["name"].as_str().unwrap(), - package["version"].as_str().unwrap(), - package["description"] - .as_str() - .map(|d| if d.is_empty() { - d.to_string() - } else { - format!("\n{}\n", d) - }) - .unwrap_or_default() - ); - } - } - Command::Publish => { - if project.manifest().private { - anyhow::bail!("package is private, cannot publish"); - } - - let encoder = GzEncoder::new(vec![], Compression::default()); - let mut archive = TarBuilder::new(encoder); - - let cwd = &CWD.to_path_buf(); - - let mut walk_builder = WalkBuilder::new(cwd); - walk_builder.add_custom_ignore_filename(".pesdeignore"); - let mut overrides = OverrideBuilder::new(cwd); - - for packages_folder in IGNORED_FOLDERS { - overrides.add(&format!("!{}", packages_folder))?; - } - - walk_builder.overrides(overrides.build()?); - - for entry in walk_builder.build() { - let entry = entry?; - let path = entry.path(); - let relative_path = path.strip_prefix(cwd)?; - let entry_type = entry - .file_type() - .ok_or(anyhow::anyhow!("failed to get file type"))?; - - if relative_path.as_os_str().is_empty() { - continue; - } - - if entry_type.is_file() { - archive.append_path_with_name(path, relative_path)?; - } else if entry_type.is_dir() { - archive.append_dir(relative_path, path)?; - } - } - - let archive = archive.into_inner()?.finish()?; - - if archive.len() > MAX_ARCHIVE_SIZE { - anyhow::bail!( - "archive is too big ({} bytes), max {MAX_ARCHIVE_SIZE}. aborting...", - archive.len() - ); - } - - let part = reqwest::blocking::multipart::Part::bytes(archive) - .file_name("tarball.tar.gz") - .mime_str("application/gzip")?; - - let index = project.indices().get(DEFAULT_INDEX_NAME).unwrap(); - - let mut request = REQWEST_CLIENT - .post(format!("{}/v0/packages", index.config()?.api())) - .multipart(reqwest::blocking::multipart::Form::new().part("tarball", part)); - - if let Some(token) = index.registry_auth_token() { - request = request.header(AUTHORIZATION, format!("Bearer {token}")); - } else { - request = request.header(AUTHORIZATION, ""); - } - - println!("{}", send_request(request)?.text()?); - } - Command::Patch { package } => { - let lockfile = project - .lockfile()? - .ok_or(anyhow::anyhow!("lockfile not found"))?; - - let resolved_pkg = lockfile - .children - .get(&package.0) - .and_then(|versions| versions.get(&package.1)) - .ok_or(anyhow::anyhow!("package not found in lockfile"))?; - - let dir = DIRS - .data_dir() - .join("patches") - .join(format!("{}@{}", package.0.escaped(), package.1)) - .join(Utc::now().timestamp().to_string()); - - if dir.exists() { - anyhow::bail!( - "patch already exists. remove the directory {} to create a new patch", - dir.display() - ); - } - - create_dir_all(&dir)?; - - let project = Lazy::force_mut(&mut project); - let url = resolved_pkg.pkg_ref.resolve_url(project)?; - - let index = project.indices().get(DEFAULT_INDEX_NAME).unwrap(); - - resolved_pkg.pkg_ref.download( - &REQWEST_CLIENT, - index.registry_auth_token().map(|t| t.to_string()), - url.as_ref(), - index.credentials_fn().cloned(), - &dir, - )?; - - match &resolved_pkg.pkg_ref { - PackageRef::Git(_) => {} - _ => { - setup_patches_repo(&dir)?; - } - } - - println!("done! modify the files in {} and run `{} patch-commit ` to commit the changes", dir.display(), env!("CARGO_BIN_NAME")); - } - Command::PatchCommit { dir } => { - let name = dir - .parent() - .and_then(|p| p.file_name()) - .and_then(|f| f.to_str()) - .unwrap(); - - let patch_path = project.path().join(PATCHES_FOLDER); - create_dir_all(&patch_path)?; - - let patch_path = patch_path.join(format!("{name}.patch")); - if patch_path.exists() { - anyhow::bail!( - "patch already exists. remove the file {} to create a new patch", - patch_path.display() - ); - } - - let patches = create_patch(&dir)?; - - write(&patch_path, patches)?; - - remove_dir_all(&dir)?; - - println!( - "done! to apply the patch, run `{} install`", - env!("CARGO_BIN_NAME") - ); - } - Command::Init => { - if CWD.join(MANIFEST_FILE_NAME).exists() { - anyhow::bail!("manifest already exists"); - } - - let default_name = CWD.file_name().and_then(|s| s.to_str()); - - let mut name = - Text::new("What is the name of the package?").with_validator(|name: &str| { - Ok(match StandardPackageName::from_str(name) { - Ok(_) => Validation::Valid, - Err(e) => Validation::Invalid(e.into()), - }) - }); - - if let Some(name_str) = default_name { - name = name.with_initial_value(name_str); - } - - let name = name.prompt()?; - - let path_style = - Select::new("What style of paths do you want to use?", vec!["roblox"]).prompt()?; - let path_style = match path_style { - "roblox" => PathStyle::Roblox { - place: Default::default(), - }, - _ => unreachable!(), - }; - - let description = Text::new("What is the description of the package?").prompt()?; - let license = Text::new("What is the license of the package?").prompt()?; - let authors = Text::new("Who are the authors of the package? (split using ;)") - .prompt()? - .split(';') - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty()) - .collect::>(); - let repository = Text::new("What is the repository of the package?").prompt()?; - - let private = Select::new("Is this package private?", vec!["yes", "no"]).prompt()?; - let private = private == "yes"; - - let realm = Select::new( - "What is the realm of the package?", - vec!["shared", "server", "dev"], - ) - .prompt()?; - - let realm = match realm { - "shared" => Realm::Shared, - "server" => Realm::Server, - "dev" => Realm::Development, - _ => unreachable!(), - }; - - let manifest = Manifest { - name: name.parse()?, - version: Version::parse("0.1.0")?, - exports: Default::default(), - path_style, - private, - realm: Some(realm), - indices: BTreeMap::from([( - DEFAULT_INDEX_NAME.to_string(), - DEFAULT_INDEX_URL.to_string(), - )]), - #[cfg(feature = "wally")] - sourcemap_generator: None, - overrides: Default::default(), - - dependencies: Default::default(), - peer_dependencies: Default::default(), - description: none_if_empty!(description), - license: none_if_empty!(license), - authors: none_if_empty!(authors), - repository: none_if_empty!(repository), - }; - - manifest.write(CWD.to_path_buf())?; - } - Command::Add { - package, - realm, - peer, - } => { - let mut manifest = project.manifest().clone(); - - let specifier = match package.0.clone() { - PackageName::Standard(name) => { - DependencySpecifier::Registry(RegistryDependencySpecifier { - name, - version: package.1, - realm, - index: DEFAULT_INDEX_NAME.to_string(), - }) - } - #[cfg(feature = "wally")] - PackageName::Wally(name) => DependencySpecifier::Wally( - pesde::dependencies::wally::WallyDependencySpecifier { - name, - version: package.1, - realm, - index_url: crate::cli::DEFAULT_WALLY_INDEX_URL.parse().unwrap(), - }, - ), - }; - - fn insert_into( - deps: &mut BTreeMap, - specifier: DependencySpecifier, - name: PackageName, - ) { - macro_rules! not_taken { - ($key:expr) => { - (!deps.contains_key(&$key)).then_some($key) - }; - } - - let key = not_taken!(name.name().to_string()) - .or_else(|| not_taken!(format!("{}/{}", name.scope(), name.name()))) - .or_else(|| not_taken!(name.to_string())) - .unwrap(); - deps.insert(key, specifier); - } - - if peer { - insert_into( - &mut manifest.peer_dependencies, - specifier, - package.0.clone(), - ); - } else { - insert_into(&mut manifest.dependencies, specifier, package.0.clone()); - } - - manifest.write(CWD.to_path_buf())? - } - Command::Remove { package } => { - let mut manifest = project.manifest().clone(); - - for dependencies in [&mut manifest.dependencies, &mut manifest.peer_dependencies] { - dependencies.retain(|_, d| { - if let DependencySpecifier::Registry(registry) = d { - match &package { - PackageName::Standard(name) => ®istry.name != name, - #[cfg(feature = "wally")] - PackageName::Wally(_) => true, - } - } else { - cfg_if! { - if #[cfg(feature = "wally")] { - #[allow(clippy::collapsible_else_if)] - if let DependencySpecifier::Wally(wally) = d { - match &package { - PackageName::Standard(_) => true, - PackageName::Wally(name) => &wally.name != name, - } - } else { - true - } - } else { - true - } - } - } - }); - } - - manifest.write(project.path())? - } - Command::Outdated => { - let project = Lazy::force_mut(&mut project); - - let manifest = project.manifest().clone(); - let lockfile = manifest.dependency_graph(project, false)?; - - for (name, versions) in &lockfile.children { - for (version, resolved_pkg) in versions { - if lockfile.root_specifier(resolved_pkg).is_none() { - continue; - } - - if let PackageRef::Registry(registry) = &resolved_pkg.pkg_ref { - let latest_version = send_request(REQWEST_CLIENT.get(format!( - "{}/v0/packages/{}/{}/versions", - resolved_pkg.pkg_ref.get_index(project).config()?.api(), - registry.name.scope(), - registry.name.name() - )))? - .json::()? - .as_array() - .and_then(|a| a.last()) - .and_then(|v| v.as_str()) - .and_then(|s| s.parse::().ok()) - .ok_or(anyhow::anyhow!( - "failed to get latest version of {name}@{version}" - ))?; - - if &latest_version > version { - println!( - "{name}@{version} is outdated. latest version: {latest_version}" - ); - } - } - } - } - } - #[cfg(feature = "wally")] - Command::Convert => { - Manifest::from_path_or_convert(CWD.to_path_buf())?; - } - _ => unreachable!(), - } - - Ok(()) -} diff --git a/src/dependencies/git.rs b/src/dependencies/git.rs deleted file mode 100644 index 33bf6ce..0000000 --- a/src/dependencies/git.rs +++ /dev/null @@ -1,237 +0,0 @@ -use std::{ - fs::create_dir_all, - hash::{DefaultHasher, Hash, Hasher}, - path::Path, - sync::Arc, -}; - -use git2::{build::RepoBuilder, Repository}; -use log::{debug, error, warn}; -use semver::Version; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use url::Url; - -use crate::{ - index::{remote_callbacks, CredentialsFn}, - manifest::{update_sync_tool_files, Manifest, ManifestConvertError, Realm}, - package_name::StandardPackageName, - project::{get_index, Indices}, -}; - -/// A dependency of a package that can be downloaded from a git repository -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct GitDependencySpecifier { - /// The URL of the git repository (can be in the form of `owner/repo`, in which case it will default to GitHub) - pub repo: String, - /// The revision of the git repository to use - pub rev: String, - /// The realm of the package - #[serde(skip_serializing_if = "Option::is_none")] - pub realm: Option, -} - -/// A reference to a package that can be downloaded from a git repository -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct GitPackageRef { - /// The name of the package - pub name: StandardPackageName, - /// The version of the package - pub version: Version, - /// The URL of the git repository - pub repo_url: Url, - /// The revision of the git repository to use - pub rev: String, -} - -/// An error that occurred while downloading a git repository -#[derive(Debug, Error)] -pub enum GitDownloadError { - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while reading the manifest of the git repository - #[error("error reading manifest")] - ManifestRead(#[from] ManifestConvertError), - - /// An error that occurred because the URL is invalid - #[error("invalid URL")] - InvalidUrl(#[from] url::ParseError), - - /// An error that occurred while resolving a git dependency's manifest - #[error("error resolving git dependency manifest")] - Resolve(#[from] GitManifestResolveError), -} - -/// An error that occurred while resolving a git dependency's manifest -#[derive(Debug, Error)] -pub enum GitManifestResolveError { - /// An error that occurred because the scope and name could not be extracted from the URL - #[error("could not extract scope and name from URL: {0}")] - ScopeAndNameFromUrl(Url), - - /// An error that occurred because the package name is invalid - #[error("invalid package name")] - InvalidPackageName(#[from] crate::package_name::StandardPackageNameValidationError), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), -} - -fn to_snake_case(s: &str) -> String { - s.chars() - .enumerate() - .map(|(i, c)| { - if c.is_uppercase() { - format!("{}{}", if i == 0 { "" } else { "_" }, c.to_lowercase()) - } else if c == '-' { - "_".to_string() - } else { - c.to_string() - } - }) - .collect() -} - -pub(crate) fn manifest(path: &Path, url: &Url) -> Result { - Manifest::from_path_or_convert(path).or_else(|_| { - let (scope, name) = url - .path_segments() - .and_then(|mut s| { - let scope = s.next(); - let name = s.next(); - - if let (Some(scope), Some(name)) = (scope, name) { - Some((scope.to_string(), name.to_string())) - } else { - None - } - }) - .ok_or_else(|| GitManifestResolveError::ScopeAndNameFromUrl(url.clone()))?; - - let manifest = Manifest { - name: StandardPackageName::new( - &to_snake_case(&scope), - &to_snake_case(name.trim_end_matches(".git")), - )?, - version: Version::new(0, 1, 0), - description: None, - license: None, - authors: None, - repository: None, - exports: Default::default(), - path_style: Default::default(), - private: true, - realm: None, - indices: Default::default(), - #[cfg(feature = "wally")] - sourcemap_generator: None, - overrides: Default::default(), - - dependencies: Default::default(), - peer_dependencies: Default::default(), - }; - - manifest.write(path).unwrap(); - - update_sync_tool_files(path, manifest.name.name().to_string())?; - - Ok(manifest) - }) -} - -impl GitDependencySpecifier { - pub(crate) fn resolve( - &self, - cache_dir: &Path, - indices: &Indices, - ) -> Result<(Manifest, Url, String), GitDownloadError> { - debug!("resolving git dependency {}", self.repo); - - // should also work with ssh urls - let repo_url = if self.repo.contains(':') { - debug!("resolved git repository name to: {}", self.repo); - Url::parse(&self.repo) - } else { - debug!("assuming git repository is a name: {}", self.repo); - Url::parse(&format!("https://github.com/{}.git", &self.repo)) - }?; - - debug!("resolved git repository url to: {}", &repo_url); - - let mut hasher = DefaultHasher::new(); - repo_url.hash(&mut hasher); - self.rev.hash(&mut hasher); - let repo_hash = hasher.finish(); - - let dest = cache_dir.join("git").join(repo_hash.to_string()); - - let repo = if !dest.exists() { - create_dir_all(&dest)?; - - let mut fetch_options = git2::FetchOptions::new(); - fetch_options.remote_callbacks(remote_callbacks!(get_index(indices, None))); - - RepoBuilder::new() - .fetch_options(fetch_options) - .clone(repo_url.as_ref(), &dest)? - } else { - Repository::open(&dest)? - }; - - let obj = repo.revparse_single(&self.rev)?; - debug!("resolved git revision {} to: {}", self.rev, obj.id()); - - repo.reset(&obj, git2::ResetType::Hard, None)?; - - Ok((manifest(&dest, &repo_url)?, repo_url, obj.id().to_string())) - } -} - -impl GitPackageRef { - /// Downloads the package to the specified destination - pub fn download>( - &self, - dest: P, - credentials_fn: Option>, - ) -> Result<(), GitDownloadError> { - let mut fetch_options = git2::FetchOptions::new(); - let mut remote_callbacks = git2::RemoteCallbacks::new(); - let credentials_fn = credentials_fn.map(|f| f()); - - if let Some(credentials_fn) = credentials_fn { - debug!("authenticating this git clone with credentials"); - remote_callbacks.credentials(credentials_fn); - } else { - debug!("no credentials provided for this git clone"); - } - - fetch_options.remote_callbacks(remote_callbacks); - - let repo = RepoBuilder::new() - .fetch_options(fetch_options) - .clone(self.repo_url.as_ref(), dest.as_ref())?; - - let obj = repo.revparse_single(&self.rev)?; - - if self.rev != obj.id().to_string() { - warn!( - "git package ref {} resolved to a different revision: {}. this shouldn't happen", - self.rev, - obj.id() - ); - } - - repo.reset(&obj, git2::ResetType::Hard, None)?; - - Ok(()) - } -} diff --git a/src/dependencies/mod.rs b/src/dependencies/mod.rs deleted file mode 100644 index f246093..0000000 --- a/src/dependencies/mod.rs +++ /dev/null @@ -1,443 +0,0 @@ -use std::{ - fmt::Display, - fs::create_dir_all, - path::{Path, PathBuf}, - sync::Arc, -}; - -use cfg_if::cfg_if; -use log::debug; -use reqwest::header::AUTHORIZATION; -use semver::Version; -use serde::{de::IntoDeserializer, Deserialize, Deserializer, Serialize}; -use serde_yaml::Value; -use thiserror::Error; -use url::Url; - -use crate::{ - dependencies::{ - git::{GitDependencySpecifier, GitPackageRef}, - registry::{RegistryDependencySpecifier, RegistryPackageRef}, - resolution::RootLockfileNode, - }, - index::{CredentialsFn, Index}, - manifest::{ManifestWriteError, Realm}, - multithread::MultithreadedJob, - package_name::PackageName, - project::{get_index, get_index_by_url, InstallProjectError, Project}, -}; - -/// Git dependency related stuff -pub mod git; -/// Registry dependency related stuff -pub mod registry; -/// Resolution -pub mod resolution; -/// Wally dependency related stuff -#[cfg(feature = "wally")] -pub mod wally; - -// To improve developer experience, we resolve the type of the dependency specifier with a custom deserializer, so that the user doesn't have to specify the type of the dependency -/// A dependency of a package -#[derive(Serialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(untagged)] -pub enum DependencySpecifier { - /// A dependency that can be downloaded from a registry - Registry(RegistryDependencySpecifier), - /// A dependency that can be downloaded from a git repository - Git(GitDependencySpecifier), - /// A dependency that can be downloaded from a wally registry - #[cfg(feature = "wally")] - Wally(wally::WallyDependencySpecifier), -} - -impl DependencySpecifier { - /// Gets the name (or repository) of the specifier - pub fn name(&self) -> String { - match self { - DependencySpecifier::Registry(registry) => registry.name.to_string(), - DependencySpecifier::Git(git) => git.repo.to_string(), - #[cfg(feature = "wally")] - DependencySpecifier::Wally(wally) => wally.name.to_string(), - } - } - - /// Gets the version (or revision) of the specifier - pub fn version(&self) -> String { - match self { - DependencySpecifier::Registry(registry) => registry.version.to_string(), - DependencySpecifier::Git(git) => git.rev.clone(), - #[cfg(feature = "wally")] - DependencySpecifier::Wally(wally) => wally.version.to_string(), - } - } - - /// Gets the realm of the specifier - pub fn realm(&self) -> Option<&Realm> { - match self { - DependencySpecifier::Registry(registry) => registry.realm.as_ref(), - DependencySpecifier::Git(git) => git.realm.as_ref(), - #[cfg(feature = "wally")] - DependencySpecifier::Wally(wally) => wally.realm.as_ref(), - } - } -} - -impl<'de> Deserialize<'de> for DependencySpecifier { - fn deserialize>(deserializer: D) -> Result { - let yaml = Value::deserialize(deserializer)?; - - let result = if yaml.get("repo").is_some() { - GitDependencySpecifier::deserialize(yaml.into_deserializer()) - .map(DependencySpecifier::Git) - } else if yaml.get("name").is_some() { - RegistryDependencySpecifier::deserialize(yaml.into_deserializer()) - .map(DependencySpecifier::Registry) - } else if yaml.get("wally").is_some() { - cfg_if! { - if #[cfg(feature = "wally")] { - wally::WallyDependencySpecifier::deserialize(yaml.into_deserializer()) - .map(DependencySpecifier::Wally) - } else { - Err(serde::de::Error::custom("wally is not enabled")) - } - } - } else { - Err(serde::de::Error::custom("invalid dependency")) - }; - - result.map_err(|e| serde::de::Error::custom(e.to_string())) - } -} - -// Here we don't use a custom deserializer, because this is exposed to the user only from the lock file, which mustn't be edited manually anyway -/// A reference to a package -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(rename_all = "snake_case", tag = "type")] -pub enum PackageRef { - /// A reference to a package that can be downloaded from a registry - Registry(RegistryPackageRef), - /// A reference to a package that can be downloaded from a git repository - Git(GitPackageRef), - /// A reference to a package that can be downloaded from a wally registry - #[cfg(feature = "wally")] - Wally(wally::WallyPackageRef), -} - -/// An error that occurred while downloading a package -#[derive(Debug, Error)] -pub enum DownloadError { - /// An error that occurred while downloading a package from a registry - #[error("error downloading package {1} from registry")] - Registry(#[source] registry::RegistryDownloadError, Box), - - /// An error that occurred while downloading a package from a git repository - #[error("error downloading package {1} from git repository")] - Git(#[source] git::GitDownloadError, Box), - - /// An error that occurred while downloading a package from a wally registry - #[cfg(feature = "wally")] - #[error("error downloading package {1} from wally registry")] - Wally(#[source] wally::WallyDownloadError, Box), - - /// A URL is required for this type of package reference - #[error("a URL is required for this type of package reference")] - UrlRequired, -} - -/// An error that occurred while resolving a URL -#[derive(Debug, Error)] -pub enum UrlResolveError { - /// An error that occurred while resolving a URL of a registry package - #[error("error resolving URL of registry package")] - Registry(#[from] registry::RegistryUrlResolveError), - - /// An error that occurred while resolving a URL of a wally package - #[cfg(feature = "wally")] - #[error("error resolving URL of wally package")] - Wally(#[from] wally::ResolveWallyUrlError), -} - -impl PackageRef { - /// Gets the name of the package - pub fn name(&self) -> PackageName { - match self { - PackageRef::Registry(registry) => PackageName::Standard(registry.name.clone()), - PackageRef::Git(git) => PackageName::Standard(git.name.clone()), - #[cfg(feature = "wally")] - PackageRef::Wally(wally) => PackageName::Wally(wally.name.clone()), - } - } - - /// Gets the version of the package - pub fn version(&self) -> &Version { - match self { - PackageRef::Registry(registry) => ®istry.version, - PackageRef::Git(git) => &git.version, - #[cfg(feature = "wally")] - PackageRef::Wally(wally) => &wally.version, - } - } - - /// Returns the URL of the index - pub fn index_url(&self) -> Option { - match self { - PackageRef::Registry(registry) => Some(registry.index_url.clone()), - PackageRef::Git(_) => None, - #[cfg(feature = "wally")] - PackageRef::Wally(wally) => Some(wally.index_url.clone()), - } - } - - /// Resolves the URL of the package - pub fn resolve_url(&self, project: &mut Project) -> Result, UrlResolveError> { - Ok(match &self { - PackageRef::Registry(registry) => Some(registry.resolve_url(project.indices())?), - PackageRef::Git(_) => None, - #[cfg(feature = "wally")] - PackageRef::Wally(wally) => { - let cache_dir = project.cache_dir().to_path_buf(); - Some(wally.resolve_url(&cache_dir, project.indices_mut())?) - } - }) - } - - /// Gets the index of the package - pub fn get_index<'a>(&self, project: &'a Project) -> &'a dyn Index { - match &self.index_url() { - Some(url) => get_index_by_url(project.indices(), url), - None => get_index(project.indices(), None), - } - } - - /// Downloads the package to the specified destination - pub fn download>( - &self, - reqwest_client: &reqwest::blocking::Client, - registry_auth_token: Option, - url: Option<&Url>, - credentials_fn: Option>, - dest: P, - ) -> Result<(), DownloadError> { - match self { - PackageRef::Registry(registry) => registry - .download( - reqwest_client, - url.ok_or(DownloadError::UrlRequired)?, - registry_auth_token, - dest, - ) - .map_err(|e| DownloadError::Registry(e, Box::new(self.clone()))), - PackageRef::Git(git) => git - .download(dest, credentials_fn) - .map_err(|e| DownloadError::Git(e, Box::new(self.clone()))), - #[cfg(feature = "wally")] - PackageRef::Wally(wally) => wally - .download( - reqwest_client, - url.ok_or(DownloadError::UrlRequired)?, - registry_auth_token, - dest, - ) - .map_err(|e| DownloadError::Wally(e, Box::new(self.clone()))), - } - } -} - -/// An error that occurred while converting a manifest -#[derive(Debug, Error)] -pub enum ConvertManifestsError { - /// An error that occurred while converting the manifest - #[error("error converting the manifest")] - Manifest(#[from] crate::manifest::ManifestConvertError), - - /// An error that occurred while converting a git dependency's manifest - #[error("error converting a git dependency's manifest")] - Git(#[from] crate::dependencies::git::GitManifestResolveError), - - /// An error that occurred while reading the sourcemap - #[error("error reading the sourcemap")] - Sourcemap(#[from] std::io::Error), - - /// An error that occurred while parsing the sourcemap - #[cfg(feature = "wally")] - #[error("error parsing the sourcemap")] - Parse(#[from] serde_json::Error), - - /// An error that occurred while writing the manifest - #[error("error writing the manifest")] - Write(#[from] ManifestWriteError), - - /// A manifest is not present in a dependency, and the wally feature is not enabled - #[cfg(not(feature = "wally"))] - #[error("wally feature is not enabled, but the manifest is not present in the dependency")] - ManifestNotPresent, -} - -impl Project { - /// Downloads the project's dependencies - pub fn download( - &mut self, - lockfile: &RootLockfileNode, - ) -> Result, InstallProjectError> { - let (job, tx) = MultithreadedJob::new(); - - for (name, versions) in lockfile.children.clone() { - for (version, resolved_package) in versions { - let (_, source) = resolved_package.directory(self.path()); - - if source.exists() { - debug!("package {name}@{version} already downloaded, skipping..."); - continue; - } - - debug!( - "downloading package {name}@{version} to {}", - source.display() - ); - - create_dir_all(&source)?; - - let reqwest_client = self.reqwest_client.clone(); - let url = resolved_package.pkg_ref.resolve_url(self)?; - let index = resolved_package.pkg_ref.get_index(self); - let registry_auth_token = index.registry_auth_token().map(|t| t.to_string()); - let credentials_fn = index.credentials_fn().cloned(); - - job.execute(&tx, move || { - resolved_package.pkg_ref.download( - &reqwest_client, - registry_auth_token, - url.as_ref(), - credentials_fn, - source, - ) - }); - } - } - - Ok(job) - } - - /// Converts the manifests of the project's dependencies - #[cfg(feature = "wally")] - pub fn convert_manifests( - &self, - lockfile: &RootLockfileNode, - generate_sourcemap: F, - ) -> MultithreadedJob { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - struct SourcemapNode { - #[serde(default)] - file_paths: Vec, - } - - let (job, tx) = MultithreadedJob::new(); - - let generate_sourcemap = Arc::new(generate_sourcemap); - - for versions in lockfile.children.values() { - for resolved_package in versions.values().cloned() { - let generate_sourcemap = generate_sourcemap.clone(); - let self_path = self.path().to_path_buf(); - - job.execute(&tx, move || { - let source = match &resolved_package.pkg_ref { - PackageRef::Wally(_) | PackageRef::Git(_) => { - resolved_package.directory(self_path).1 - } - _ => return Ok(()), - }; - - let mut manifest = match &resolved_package.pkg_ref { - PackageRef::Git(git) => { - crate::dependencies::git::manifest(&source, &git.repo_url)? - } - _ => crate::manifest::Manifest::from_path_or_convert(&source)?, - }; - - generate_sourcemap(source.to_path_buf()); - - let sourcemap = source.join("sourcemap.json"); - let sourcemap: SourcemapNode = if sourcemap.exists() { - serde_json::from_str(&std::fs::read_to_string(&sourcemap)?)? - } else { - log::warn!("sourcemap for {resolved_package} not found, skipping..."); - return Ok(()); - }; - - manifest.exports.lib = sourcemap - .file_paths - .into_iter() - .find(|path| { - path.extension() - .is_some_and(|ext| ext == "lua" || ext == "luau") - }) - .or_else(|| Some(relative_path::RelativePathBuf::from("true"))); - - manifest.write(&source)?; - - Ok(()) - }); - } - } - - job - } - - /// Errors if dependencies don't have manifests, enable the `wally` feature to convert them - #[cfg(not(feature = "wally"))] - pub fn convert_manifests( - &self, - lockfile: &RootLockfileNode, - _generate_sourcemap: F, - ) -> Result<(), ConvertManifestsError> { - for versions in lockfile.children.values() { - for resolved_package in versions.values() { - let source = match &resolved_package.pkg_ref { - PackageRef::Git(_) => resolved_package.directory(self.path()).1, - _ => continue, - }; - - if match &resolved_package.pkg_ref { - PackageRef::Git(git) => { - crate::dependencies::git::manifest(&source, &git.repo_url).is_err() - } - _ => crate::manifest::Manifest::from_path_or_convert(&source).is_err(), - } { - return Err(ConvertManifestsError::ManifestNotPresent); - } - } - } - - Ok(()) - } -} - -impl Display for PackageRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}@{}", self.name(), self.version()) - } -} - -pub(crate) fn maybe_authenticated_request( - reqwest_client: &reqwest::blocking::Client, - url: &str, - registry_auth_token: Option, -) -> reqwest::blocking::RequestBuilder { - let mut builder = reqwest_client.get(url); - debug!("sending request to {}", url); - - if let Some(token) = registry_auth_token { - let hidden_token = token - .chars() - .enumerate() - .map(|(i, c)| if i <= 8 { c } else { '*' }) - .collect::(); - debug!("with registry token {hidden_token}"); - builder = builder.header(AUTHORIZATION, format!("Bearer {token}")); - } - - builder -} diff --git a/src/dependencies/registry.rs b/src/dependencies/registry.rs deleted file mode 100644 index 1b8aa13..0000000 --- a/src/dependencies/registry.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::path::Path; - -use log::{debug, error}; -use semver::{Version, VersionReq}; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use url::Url; - -use crate::{ - dependencies::maybe_authenticated_request, - manifest::Realm, - package_name::StandardPackageName, - project::{get_index_by_url, Indices, DEFAULT_INDEX_NAME}, -}; - -fn default_index_name() -> String { - DEFAULT_INDEX_NAME.to_string() -} - -/// A dependency of a package that can be downloaded from a registry -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct RegistryDependencySpecifier { - /// The name of the package - pub name: StandardPackageName, - /// The version requirement of the package - pub version: VersionReq, - /// The name of the index to use - #[serde(default = "default_index_name")] - pub index: String, - /// The realm of the package - #[serde(skip_serializing_if = "Option::is_none")] - pub realm: Option, -} - -/// A reference to a package that can be downloaded from a registry -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct RegistryPackageRef { - /// The name of the package - pub name: StandardPackageName, - /// The version of the package - pub version: Version, - /// The index URL of the package - pub index_url: Url, -} - -/// An error that occurred while downloading a package from a registry -#[derive(Debug, Error)] -pub enum RegistryDownloadError { - /// An error that occurred while interacting with reqwest - #[error("error interacting with reqwest")] - Reqwest(#[from] reqwest::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while reading the index config - #[error("error with the index config")] - IndexConfig(#[from] crate::index::ConfigError), - - /// The package was not found on the registry - #[error("package {0} not found on the registry, but found in the index")] - NotFound(StandardPackageName), - - /// The user is unauthorized to download the package - #[error("unauthorized to download package {0}")] - Unauthorized(StandardPackageName), - - /// An HTTP error occurred - #[error("http error {0}: the server responded with {1}")] - Http(reqwest::StatusCode, String), - - /// An error occurred while parsing the api URL - #[error("error parsing the API URL")] - UrlParse(#[from] url::ParseError), -} - -/// An error that occurred while resolving the url of a registry package -#[derive(Debug, Error)] -pub enum RegistryUrlResolveError { - /// An error that occurred while reading the index config - #[error("error with the index config")] - IndexConfig(#[from] crate::index::ConfigError), - - /// An error occurred while parsing the api URL - #[error("error parsing the API URL")] - UrlParse(#[from] url::ParseError), -} - -impl RegistryPackageRef { - /// Resolves the download URL of the package - pub fn resolve_url(&self, indices: &Indices) -> Result { - let index = get_index_by_url(indices, &self.index_url); - let config = index.config()?; - - let url = config - .download() - .replace("{PACKAGE_AUTHOR}", self.name.scope()) - .replace("{PACKAGE_NAME}", self.name.name()) - .replace("{PACKAGE_VERSION}", &self.version.to_string()); - - Ok(Url::parse(&url)?) - } - - /// Downloads the package to the specified destination - pub fn download>( - &self, - reqwest_client: &reqwest::blocking::Client, - url: &Url, - registry_auth_token: Option, - dest: P, - ) -> Result<(), RegistryDownloadError> { - debug!( - "downloading registry package {}@{} from {}", - self.name, self.version, url - ); - - let response = - maybe_authenticated_request(reqwest_client, url.as_str(), registry_auth_token) - .send()?; - - if !response.status().is_success() { - return match response.status() { - reqwest::StatusCode::NOT_FOUND => { - Err(RegistryDownloadError::NotFound(self.name.clone())) - } - reqwest::StatusCode::UNAUTHORIZED => { - Err(RegistryDownloadError::Unauthorized(self.name.clone())) - } - _ => Err(RegistryDownloadError::Http( - response.status(), - response.text()?, - )), - }; - } - - let bytes = response.bytes()?; - - let mut decoder = flate2::read::GzDecoder::new(bytes.as_ref()); - let mut archive = tar::Archive::new(&mut decoder); - - archive.unpack(&dest)?; - - Ok(()) - } -} diff --git a/src/dependencies/resolution.rs b/src/dependencies/resolution.rs deleted file mode 100644 index 566a675..0000000 --- a/src/dependencies/resolution.rs +++ /dev/null @@ -1,596 +0,0 @@ -use std::{ - collections::{BTreeMap, HashMap, HashSet, VecDeque}, - fmt::Display, - path::{Path, PathBuf}, -}; - -use log::debug; -use semver::{Version, VersionReq}; -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -use crate::{ - dependencies::{ - git::{GitDownloadError, GitPackageRef}, - registry::RegistryPackageRef, - DependencySpecifier, PackageRef, - }, - index::{Index, IndexFileEntry, IndexPackageError}, - manifest::{DependencyType, Manifest, OverrideKey, Realm}, - package_name::{PackageName, StandardPackageName}, - project::{get_index, get_index_by_url, Indices, Project, ReadLockfileError}, - DEV_PACKAGES_FOLDER, INDEX_FOLDER, PACKAGES_FOLDER, SERVER_PACKAGES_FOLDER, -}; - -/// A mapping of packages to something -pub type PackageMap = BTreeMap>; - -/// The root node of the dependency graph -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct RootLockfileNode { - /// The name of the package - pub name: StandardPackageName, - - /// Dependency overrides - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub overrides: BTreeMap, - - /// The specifiers of the root packages - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub specifiers: PackageMap<(DependencySpecifier, String)>, - - /// All nodes in the dependency graph - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub children: PackageMap, -} - -impl RootLockfileNode { - /// Returns the specifier of the root package - pub fn root_specifier( - &self, - resolved_package: &ResolvedPackage, - ) -> Option<&(DependencySpecifier, String)> { - self.specifiers - .get(&resolved_package.pkg_ref.name()) - .and_then(|versions| versions.get(resolved_package.pkg_ref.version())) - } -} - -/// A node in the dependency graph -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ResolvedPackage { - /// The reference to the package - pub pkg_ref: PackageRef, - /// The dependencies of the package - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub dependencies: BTreeMap, - /// The realm of the package - pub realm: Realm, - /// The type of the dependency - #[serde(default, skip_serializing_if = "crate::is_default")] - pub dep_type: DependencyType, -} - -impl Display for ResolvedPackage { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.pkg_ref) - } -} - -pub(crate) fn packages_folder<'a>(realm: Realm) -> &'a str { - match realm { - Realm::Shared => PACKAGES_FOLDER, - Realm::Server => SERVER_PACKAGES_FOLDER, - Realm::Development => DEV_PACKAGES_FOLDER, - } -} - -impl ResolvedPackage { - pub(crate) fn packages_folder(&self) -> &str { - packages_folder(self.realm) - } - - /// Returns the directory of the package in the project, and the parent of the directory - pub fn directory>(&self, project_path: P) -> (PathBuf, PathBuf) { - let name = self.pkg_ref.name().escaped(); - let container_path = project_path - .as_ref() - .join(self.packages_folder()) - .join(INDEX_FOLDER) - .join(&name) - .join(self.pkg_ref.version().to_string()); - - (container_path.clone(), container_path.join(&name)) - } -} - -macro_rules! find_highest { - ($iter:expr, $version:expr) => { - $iter - .filter(|v| $version.matches(v)) - .max_by(|a, b| a.cmp(&b)) - .cloned() - }; -} - -fn find_version_from_index( - root: &mut RootLockfileNode, - index: &dyn Index, - specifier: &DependencySpecifier, - name: PackageName, - version_req: &VersionReq, -) -> Result { - let index_entries = index - .package(&name) - .map_err(|e| ResolveError::IndexPackage(e, name.to_string()))? - .ok_or_else(|| ResolveError::PackageNotFound(name.to_string()))?; - - let resolved_versions = root.children.entry(name).or_default(); - - // try to find the highest already downloaded version that satisfies the requirement, otherwise find the highest satisfying version in the index - let Some(version) = find_highest!(resolved_versions.keys(), version_req) - .or_else(|| find_highest!(index_entries.iter().map(|v| &v.version), version_req)) - else { - return Err(ResolveError::NoSatisfyingVersion(Box::new( - specifier.clone(), - ))); - }; - - Ok(index_entries - .into_iter() - .find(|e| e.version.eq(&version)) - .unwrap()) -} - -fn find_realm(a: &Realm, b: &Realm) -> Realm { - if a == b { - return *a; - } - - Realm::Shared -} - -/// An error that occurred while resolving dependencies -#[derive(Debug, Error)] -pub enum ResolveError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred because a registry dependency conflicts with a git dependency - #[error("registry dependency {0}@{1} conflicts with git dependency")] - RegistryConflict(String, Version), - - /// An error that occurred because a git dependency conflicts with a registry dependency - #[error("git dependency {0}@{1} conflicts with registry dependency")] - GitConflict(String, Version), - - /// An error that occurred because no satisfying version was found for a dependency - #[error("no satisfying version found for dependency {0:?}")] - NoSatisfyingVersion(Box), - - /// An error that occurred while downloading a package from a git repository - #[error("error downloading git package")] - GitDownload(#[from] GitDownloadError), - - /// An error that occurred because a package was not found in the index - #[error("package {0} not found in index")] - PackageNotFound(String), - - /// An error that occurred while getting a package from the index - #[error("failed to get package {1} from index")] - IndexPackage(#[source] IndexPackageError, String), - - /// An error that occurred while reading the lockfile - #[error("failed to read lockfile")] - LockfileRead(#[from] ReadLockfileError), - - /// An error that occurred because the lockfile is out of date - #[error("out of date lockfile")] - OutOfDateLockfile, - - /// An error that occurred because two realms are incompatible - #[error("incompatible realms for package {0} (package specified {1}, user specified {2})")] - IncompatibleRealms(String, Realm, Realm), - - /// An error that occurred because a peer dependency is not installed - #[error("peer dependency {0}@{1} is not installed")] - PeerNotInstalled(String, Version), - - /// An error that occurred while cloning a wally index - #[cfg(feature = "wally")] - #[error("error cloning wally index")] - CloneWallyIndex(#[from] crate::dependencies::wally::CloneWallyIndexError), - - /// An error that occurred while parsing a URL - #[error("error parsing URL")] - UrlParse(#[from] url::ParseError), -} - -fn get_by_maybe_url<'a>(indices: &'a Indices, maybe_url: &'a str) -> &'a dyn Index { - if let Ok(url) = maybe_url.parse() { - get_index_by_url(indices, &url) - } else { - get_index(indices, Some(maybe_url)) - } -} - -impl Manifest { - fn missing_dependencies( - &self, - root: &mut RootLockfileNode, - locked: bool, - project: &Project, - ) -> Result, ResolveError> { - Ok(if let Some(old_root) = project.lockfile()? { - if self.name != old_root.name && locked { - return Err(ResolveError::OutOfDateLockfile); - } - - if self.overrides != old_root.overrides { - // TODO: resolve only the changed dependencies (will this be worth it?) - debug!("overrides have changed, resolving all dependencies"); - return Ok(self.dependencies()); - } - - debug!("lockfile found, resolving dependencies from it"); - let mut missing = BTreeMap::new(); - - let current_dependencies = self.dependencies(); - let current_specifiers = current_dependencies - .clone() - .into_iter() - .map(|(desired_name, (specifier, _))| (specifier, desired_name)) - .collect::>(); - - // populate the new lockfile with all root dependencies (and their dependencies) from the old lockfile - for (name, versions) in &old_root.children { - for (version, resolved_package) in versions { - let Some((old_specifier, desired_name)) = old_root - .root_specifier(resolved_package) - .and_then(|(old_specifier, _)| { - current_specifiers - .get(old_specifier) - .map(|desired_name| (old_specifier, desired_name)) - }) - else { - continue; - }; - - root.specifiers.entry(name.clone()).or_default().insert( - version.clone(), - (old_specifier.clone(), desired_name.clone()), - ); - - let mut queue = VecDeque::from([(resolved_package, 0usize)]); - - while let Some((resolved_package, depth)) = queue.pop_front() { - debug!( - "{}resolved {resolved_package} from lockfile", - "\t".repeat(depth) - ); - - root.children - .entry(resolved_package.pkg_ref.name()) - .or_default() - .insert( - resolved_package.pkg_ref.version().clone(), - resolved_package.clone(), - ); - - for (dep_name, (dep_version, _)) in &resolved_package.dependencies { - if root - .children - .get(dep_name) - .and_then(|v| v.get(dep_version)) - .is_some() - { - continue; - } - - let Some(dep) = old_root - .children - .get(dep_name) - .and_then(|v| v.get(dep_version)) - else { - return Err(ResolveError::OutOfDateLockfile); - }; - - queue.push_back((dep, depth + 1)); - } - } - } - } - - let old_specifiers = old_root - .specifiers - .values() - .flat_map(|v| v.values()) - .map(|(specifier, _)| specifier) - .collect::>(); - - // resolve new, or modified, dependencies from the manifest - for (desired_name, (specifier, dep_type)) in current_dependencies { - if old_specifiers.contains(&specifier) { - continue; - } - - if locked { - return Err(ResolveError::OutOfDateLockfile); - } - - missing.insert(desired_name, (specifier.clone(), dep_type)); - } - - debug!( - "resolved {} dependencies from lockfile. new dependencies: {}", - old_root.children.len(), - missing.len() - ); - - missing - } else { - debug!("no lockfile found, resolving all dependencies"); - self.dependencies() - }) - } - - /// Resolves the dependency graph for the project - pub fn dependency_graph( - &self, - project: &mut Project, - locked: bool, - ) -> Result { - debug!("resolving dependency graph for project {}", self.name); - // try to reuse versions (according to semver specifiers) to decrease the amount of downloads and storage - let mut root = RootLockfileNode { - name: self.name.clone(), - overrides: self.overrides.clone(), - specifiers: Default::default(), - children: Default::default(), - }; - - let missing_dependencies = self.missing_dependencies(&mut root, locked, project)?; - - if missing_dependencies.is_empty() { - debug!("no dependencies left to resolve, finishing..."); - return Ok(root); - } - - let overrides = self - .overrides - .iter() - .flat_map(|(k, spec)| k.0.iter().map(|path| (path, spec.clone()))) - .collect::>(); - - debug!("resolving {} dependencies", missing_dependencies.len()); - - let mut queue = missing_dependencies - .into_iter() - .map(|(desired_name, (specifier, dep_type))| { - (desired_name, specifier, dep_type, None, vec![]) - }) - .collect::>(); - - while let Some((desired_name, specifier, dep_type, dependant, mut path)) = queue.pop_front() - { - let depth = path.len(); - - let (pkg_ref, default_realm, dependencies) = match &specifier { - DependencySpecifier::Registry(registry_dependency) => { - // needed because of overrides, which are expected to use the project's indices rather than URLs - let index = get_by_maybe_url(project.indices(), ®istry_dependency.index); - - let entry = find_version_from_index( - &mut root, - index, - &specifier, - registry_dependency.name.clone().into(), - ®istry_dependency.version, - )?; - - debug!( - "{}resolved registry dependency {} to {}", - "\t".repeat(depth), - registry_dependency.name, - entry.version - ); - - ( - PackageRef::Registry(RegistryPackageRef { - name: registry_dependency.name.clone(), - version: entry.version, - index_url: index.url().clone(), - }), - entry.realm, - entry.dependencies, - ) - } - DependencySpecifier::Git(git_dependency) => { - let (manifest, url, rev) = - git_dependency.resolve(project.cache_dir(), project.indices())?; - - debug!( - "{}resolved git dependency {} to {url}#{rev}", - "\t".repeat(depth), - git_dependency.repo - ); - - ( - PackageRef::Git(GitPackageRef { - name: manifest.name.clone(), - version: manifest.version.clone(), - repo_url: url, - rev, - }), - manifest.realm, - manifest.dependencies(), - ) - } - #[cfg(feature = "wally")] - DependencySpecifier::Wally(wally_dependency) => { - let cache_dir = project.cache_dir().to_path_buf(); - let index = crate::dependencies::wally::clone_wally_index( - &cache_dir, - project.indices_mut(), - &wally_dependency.index_url, - )?; - - let entry = find_version_from_index( - &mut root, - &index, - &specifier, - wally_dependency.name.clone().into(), - &wally_dependency.version, - )?; - - debug!( - "{}resolved wally dependency {} to {}", - "\t".repeat(depth), - wally_dependency.name, - entry.version - ); - - ( - PackageRef::Wally(crate::dependencies::wally::WallyPackageRef { - name: wally_dependency.name.clone(), - version: entry.version, - index_url: index.url().clone(), - }), - entry.realm, - entry.dependencies, - ) - } - }; - - // if the dependency is a root dependency, it can be thought of as a normal dependency - let dep_type = if dependant.is_some() { - dep_type - } else { - DependencyType::Normal - }; - - let specifier_realm = specifier.realm().copied(); - - if let Some((dependant_name, dependant_version)) = dependant { - root.children - .get_mut(&dependant_name) - .and_then(|v| v.get_mut(&dependant_version)) - .unwrap() - .dependencies - .insert( - pkg_ref.name(), - (pkg_ref.version().clone(), desired_name.clone()), - ); - } else { - root.specifiers - .entry(pkg_ref.name()) - .or_default() - .insert(pkg_ref.version().clone(), (specifier, desired_name.clone())); - } - - let resolved_versions = root.children.entry(pkg_ref.name()).or_default(); - - if let Some(previously_resolved) = resolved_versions.get_mut(pkg_ref.version()) { - match (&pkg_ref, &previously_resolved.pkg_ref) { - (PackageRef::Registry(r), PackageRef::Git(_g)) => { - return Err(ResolveError::RegistryConflict( - r.name.to_string(), - r.version.clone(), - )); - } - (PackageRef::Git(g), PackageRef::Registry(_r)) => { - return Err(ResolveError::GitConflict( - g.name.to_string(), - g.version.clone(), - )); - } - _ => (), - } - - if previously_resolved.dep_type == DependencyType::Peer - && dep_type == DependencyType::Normal - { - previously_resolved.dep_type = dep_type; - } - - // need not resolve the package again - continue; - } - - if specifier_realm.is_some_and(|realm| realm == Realm::Shared) - && default_realm.is_some_and(|realm| realm == Realm::Server) - { - return Err(ResolveError::IncompatibleRealms( - pkg_ref.name().to_string(), - default_realm.unwrap(), - specifier_realm.unwrap(), - )); - } - - resolved_versions.insert( - pkg_ref.version().clone(), - ResolvedPackage { - pkg_ref: pkg_ref.clone(), - dependencies: Default::default(), - realm: specifier_realm - .unwrap_or_default() - .or(default_realm.unwrap_or_default()), - dep_type, - }, - ); - - path.push(desired_name); - - for (desired_name, (specifier, ty)) in dependencies { - let overridden = overrides.iter().find_map(|(k_path, spec)| { - (path == k_path[..k_path.len() - 1] && k_path.last() == Some(&desired_name)) - .then_some(spec) - }); - - queue.push_back(( - desired_name, - overridden.cloned().unwrap_or(specifier), - ty, - Some((pkg_ref.name(), pkg_ref.version().clone())), - path.clone(), - )); - } - } - - debug!("resolving realms and peer dependencies..."); - - for (name, versions) in root.children.clone() { - for (version, resolved_package) in versions { - if resolved_package.dep_type == DependencyType::Peer { - return Err(ResolveError::PeerNotInstalled( - resolved_package.pkg_ref.name().to_string(), - resolved_package.pkg_ref.version().clone(), - )); - } - - let mut realm = resolved_package.realm; - - for (dep_name, (dep_version, _)) in &resolved_package.dependencies { - let dep = root.children.get(dep_name).and_then(|v| v.get(dep_version)); - - if let Some(dep) = dep { - realm = find_realm(&realm, &dep.realm); - } - } - - root.children - .get_mut(&name) - .and_then(|v| v.get_mut(&version)) - .unwrap() - .realm = realm; - } - } - - debug!("finished resolving dependency graph"); - - Ok(root) - } -} diff --git a/src/dependencies/wally.rs b/src/dependencies/wally.rs deleted file mode 100644 index 3b1a0f7..0000000 --- a/src/dependencies/wally.rs +++ /dev/null @@ -1,365 +0,0 @@ -use std::{ - collections::BTreeMap, - fs::{create_dir_all, read}, - hash::{DefaultHasher, Hash, Hasher}, - io::Cursor, - path::Path, -}; - -use git2::build::RepoBuilder; -use log::{debug, error}; -use semver::{Version, VersionReq}; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use url::Url; - -use crate::{ - dependencies::{maybe_authenticated_request, DependencySpecifier}, - index::{remote_callbacks, IndexFileEntry, WallyIndex}, - manifest::{DependencyType, ManifestConvertError, Realm}, - package_name::{ - FromStrPackageNameParseError, WallyPackageName, WallyPackageNameValidationError, - }, - project::{get_wally_index, Indices}, -}; - -/// A dependency of a package that can be downloaded from a registry -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct WallyDependencySpecifier { - /// The name of the package - #[serde(rename = "wally")] - pub name: WallyPackageName, - /// The version requirement of the package - pub version: VersionReq, - /// The url of the index - pub index_url: Url, - /// The realm of the package - #[serde(skip_serializing_if = "Option::is_none")] - pub realm: Option, -} - -/// A reference to a package that can be downloaded from a registry -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] -#[serde(deny_unknown_fields)] -pub struct WallyPackageRef { - /// The name of the package - pub name: WallyPackageName, - /// The version of the package - pub version: Version, - /// The index URL of the package - pub index_url: Url, -} - -/// An error that occurred while downloading a package from a wally registry -#[derive(Debug, Error)] -pub enum WallyDownloadError { - /// An error that occurred while interacting with reqwest - #[error("error interacting with reqwest")] - Reqwest(#[from] reqwest::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// The package was not found on the registry - #[error("package {0} not found on the registry, but found in the index")] - NotFound(WallyPackageName), - - /// The user is unauthorized to download the package - #[error("unauthorized to download package {0}")] - Unauthorized(WallyPackageName), - - /// An HTTP error occurred - #[error("http error {0}: the server responded with {1}")] - Http(reqwest::StatusCode, String), - - /// An error occurred while extracting the archive - #[error("error extracting archive")] - Zip(#[from] zip::result::ZipError), - - /// An error occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error occurred while interacting with serde - #[error("error interacting with serde")] - Serde(#[from] serde_json::Error), - - /// An error occurred while parsing the api URL - #[error("error parsing URL")] - Url(#[from] url::ParseError), - - /// An error occurred while refreshing the index - #[error("error refreshing index")] - RefreshIndex(#[from] crate::index::RefreshError), - - /// An error occurred while converting the manifest - #[error("error converting manifest")] - Manifest(#[from] ManifestConvertError), -} - -/// An error that occurred while cloning a wally index -#[derive(Error, Debug)] -pub enum CloneWallyIndexError { - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while refreshing the index - #[error("error refreshing index")] - RefreshIndex(#[from] crate::index::RefreshError), -} - -pub(crate) fn clone_wally_index( - cache_dir: &Path, - indices: &mut Indices, - index_url: &Url, -) -> Result { - let mut hasher = DefaultHasher::new(); - index_url.hash(&mut hasher); - let url_hash = hasher.finish().to_string(); - - let index_path = cache_dir.join("wally_indices").join(url_hash); - - if index_path.exists() { - debug!("wally index already exists at {}", index_path.display()); - - return Ok(get_wally_index(indices, index_url, Some(&index_path))?.clone()); - } - - debug!( - "cloning wally index from {} to {}", - index_url, - index_path.display() - ); - - create_dir_all(&index_path)?; - - let mut fetch_options = git2::FetchOptions::new(); - fetch_options.remote_callbacks(remote_callbacks!(get_wally_index( - indices, - index_url, - Some(&index_path) - )?)); - - RepoBuilder::new() - .fetch_options(fetch_options) - .clone(index_url.as_ref(), &index_path)?; - - Ok(get_wally_index(indices, index_url, Some(&index_path))?.clone()) -} - -/// The configuration of a wally index -#[derive(Serialize, Deserialize, Debug)] -struct WallyIndexConfig { - /// The URL of the wally API - api: String, -} - -/// An error that occurred while resolving the URL of a wally package -#[derive(Error, Debug)] -pub enum ResolveWallyUrlError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while interacting with the index - #[error("error interacting with the index")] - Index(#[from] crate::index::ConfigError), - - /// An error that occurred while parsing the URL - #[error("error parsing URL")] - Url(#[from] url::ParseError), - - /// An error that occurred while cloning the index - #[error("error cloning index")] - CloneIndex(#[from] CloneWallyIndexError), - - /// An error that occurred while reading the index config - #[error("error reading index config")] - ReadConfig(#[from] serde_json::Error), -} - -fn read_api_url(index_path: &Path) -> Result { - let config_path = index_path.join("config.json"); - let raw_config_contents = read(config_path)?; - let config: WallyIndexConfig = serde_json::from_slice(&raw_config_contents)?; - - Ok(config.api) -} - -impl WallyPackageRef { - /// Resolves the download URL of the package - pub fn resolve_url( - &self, - cache_dir: &Path, - indices: &mut Indices, - ) -> Result { - let index = clone_wally_index(cache_dir, indices, &self.index_url)?; - - let api_url = Url::parse(&read_api_url(&index.path)?)?; - - let url = format!( - "{}/v1/package-contents/{}/{}/{}", - api_url.to_string().trim_end_matches('/'), - self.name.scope(), - self.name.name(), - self.version - ); - - Ok(Url::parse(&url)?) - } - - /// Downloads the package to the specified destination - pub fn download>( - &self, - reqwest_client: &reqwest::blocking::Client, - url: &Url, - registry_auth_token: Option, - dest: P, - ) -> Result<(), WallyDownloadError> { - let response = - maybe_authenticated_request(reqwest_client, url.as_str(), registry_auth_token) - .header( - "Wally-Version", - std::env::var("WALLY_VERSION").unwrap_or("0.3.2".to_string()), - ) - .send()?; - - if !response.status().is_success() { - return match response.status() { - reqwest::StatusCode::NOT_FOUND => { - Err(WallyDownloadError::NotFound(self.name.clone())) - } - reqwest::StatusCode::UNAUTHORIZED => { - Err(WallyDownloadError::Unauthorized(self.name.clone())) - } - _ => Err(WallyDownloadError::Http( - response.status(), - response.text()?, - )), - }; - } - - let bytes = response.bytes()?; - - let mut archive = zip::read::ZipArchive::new(Cursor::new(bytes))?; - archive.extract(dest.as_ref())?; - - Ok(()) - } -} - -#[derive(Deserialize, Clone, Debug)] -#[serde(rename_all = "kebab-case")] -pub(crate) struct WallyPackage { - pub(crate) name: WallyPackageName, - pub(crate) version: Version, - pub(crate) registry: Url, - #[serde(default)] - pub(crate) realm: Option, - #[serde(default)] - pub(crate) description: Option, - #[serde(default)] - pub(crate) license: Option, - #[serde(default)] - pub(crate) authors: Option>, - #[serde(default)] - pub(crate) private: Option, -} - -#[derive(Deserialize, Default, Clone, Debug)] -#[serde(rename_all = "kebab-case")] -pub(crate) struct WallyPlace { - #[serde(default)] - pub(crate) shared_packages: Option, - #[serde(default)] - pub(crate) server_packages: Option, -} - -#[derive(Deserialize, Clone, Debug)] -#[serde(rename_all = "kebab-case")] -pub(crate) struct WallyManifest { - pub(crate) package: WallyPackage, - #[serde(default)] - pub(crate) place: WallyPlace, - #[serde(default)] - pub(crate) dependencies: BTreeMap, - #[serde(default)] - pub(crate) server_dependencies: BTreeMap, - #[serde(default)] - pub(crate) dev_dependencies: BTreeMap, -} - -/// An error that occurred while converting a wally manifest's dependencies -#[derive(Debug, Error)] -pub enum WallyManifestDependencyError { - /// An error that occurred because the dependency specifier is invalid - #[error("invalid dependency specifier: {0}")] - InvalidDependencySpecifier(String), - - /// An error that occurred while parsing a package name - #[error("error parsing package name")] - PackageName(#[from] FromStrPackageNameParseError), - - /// An error that occurred while parsing a version requirement - #[error("error parsing version requirement")] - VersionReq(#[from] semver::Error), -} - -pub(crate) fn parse_wally_dependencies( - manifest: WallyManifest, -) -> Result, WallyManifestDependencyError> { - [ - (manifest.dependencies, Realm::Shared), - (manifest.server_dependencies, Realm::Server), - (manifest.dev_dependencies, Realm::Development), - ] - .into_iter() - .flat_map(|(deps, realm)| { - deps.into_iter() - .map(move |(desired_name, specifier)| (desired_name, specifier, realm)) - .map(|(desired_name, specifier, realm)| { - let (name, req) = specifier.split_once('@').ok_or_else(|| { - WallyManifestDependencyError::InvalidDependencySpecifier(specifier.clone()) - })?; - let name: WallyPackageName = name.parse()?; - let req: VersionReq = req.parse()?; - - Ok(( - desired_name, - DependencySpecifier::Wally(WallyDependencySpecifier { - name, - version: req, - index_url: manifest.package.registry.clone(), - realm: Some(realm), - }), - )) - }) - }) - .collect() -} - -impl TryFrom for IndexFileEntry { - type Error = WallyManifestDependencyError; - - fn try_from(value: WallyManifest) -> Result { - let dependencies = parse_wally_dependencies(value.clone())? - .into_iter() - .map(|(desired_name, specifier)| (desired_name, (specifier, DependencyType::Normal))) - .collect(); - - Ok(IndexFileEntry { - version: value.package.version, - realm: value.package.realm, - published_at: Default::default(), - description: value.package.description, - dependencies, - }) - } -} diff --git a/src/index.rs b/src/index.rs deleted file mode 100644 index 30967e9..0000000 --- a/src/index.rs +++ /dev/null @@ -1,753 +0,0 @@ -use std::{ - any::Any, - collections::{BTreeMap, BTreeSet}, - fmt::Debug, - fs::create_dir_all, - hash::Hash, - path::{Path, PathBuf}, - sync::Arc, -}; - -use chrono::{DateTime, Utc}; -use git2::{build::RepoBuilder, Remote, Repository, Signature}; -use log::debug; -use semver::Version; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use url::Url; - -use crate::{ - dependencies::DependencySpecifier, - manifest::{DependencyType, Manifest, Realm}, - package_name::PackageName, -}; - -/// Owners of a scope -pub type ScopeOwners = BTreeSet; - -/// A packages index -pub trait Index: Send + Sync + Debug + Any + 'static { - /// Gets the owners of a scope - fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError>; - - /// Creates a scope - fn create_scope_for( - &mut self, - scope: &str, - owners: &ScopeOwners, - ) -> Result; - - /// Gets a package from the index - fn package(&self, name: &PackageName) -> Result, IndexPackageError>; - - /// Creates a package version - fn create_package_version( - &mut self, - manifest: &Manifest, - uploader: &u64, - ) -> Result, CreatePackageVersionError>; - - /// Gets the index's configuration - fn config(&self) -> Result; - - /// Returns a function that gets the credentials for a git repository - fn credentials_fn(&self) -> Option<&Arc>; - - /// Returns the URL of the index's repository - fn url(&self) -> &Url; - - /// Returns the token to this index's registry - fn registry_auth_token(&self) -> Option<&str> { - None - } - - /// Updates the index - fn refresh(&self) -> Result<(), RefreshError> { - Ok(()) - } - - /// Returns this as Any - fn as_any(&self) -> &dyn Any; -} - -/// A function that gets the credentials for a git repository -pub type CredentialsFn = Box< - dyn Fn() -> Box< - dyn FnMut(&str, Option<&str>, git2::CredentialType) -> Result, - > + Send - + Sync, ->; - -/// The packages index -#[derive(Clone)] -pub struct GitIndex { - path: PathBuf, - repo_url: Url, - registry_auth_token: Option, - pub(crate) credentials_fn: Option>, -} - -impl Debug for GitIndex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("GitIndex") - .field("path", &self.path) - .field("repo_url", &self.repo_url) - .finish() - } -} - -impl Hash for GitIndex { - fn hash(&self, state: &mut H) { - self.path.hash(state); - self.repo_url.hash(state); - } -} - -impl PartialEq for GitIndex { - fn eq(&self, other: &Self) -> bool { - self.path == other.path && self.repo_url == other.repo_url - } -} - -impl Eq for GitIndex {} - -/// An error that occurred while getting the index's refspec -#[derive(Debug, Error)] -pub enum GetRefSpecError { - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// The refspec for the upstream branch was not found - #[error("refspec not found for upstream branch {0}")] - RefSpecNotFound(String), - - /// The refspec is not utf-8 - #[error("refspec not utf-8")] - RefSpecNotUtf8, - - /// The upstream branch was not found - #[error("upstream branch not found")] - UpstreamBranchNotFound, - - /// The upstream branch is not utf-8 - #[error("upstream branch not utf-8")] - UpstreamBranchNotUtf8, -} - -/// An error that occurred while refreshing the index -#[derive(Debug, Error)] -pub enum RefreshError { - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while getting the index's refspec - #[error("error getting refspec")] - GetRefSpec(#[from] GetRefSpecError), -} - -/// An error that occurred while interacting with the scope owners -#[derive(Debug, Error)] -pub enum ScopeOwnersError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while deserializing the scope owners - #[error("error deserializing scope owners")] - ScopeOwnersDeser(#[source] serde_yaml::Error), - - /// An error that occurred while committing and pushing to the index - #[error("error committing and pushing to the index")] - CommitAndPush(#[from] CommitAndPushError), -} - -/// An error that occurred while committing and pushing to the index -#[derive(Debug, Error)] -pub enum CommitAndPushError { - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while getting the index's refspec - #[error("error getting refspec")] - GetRefSpec(#[from] GetRefSpecError), -} - -/// An error that occurred while getting a package from the index -#[derive(Debug, Error)] -pub enum IndexPackageError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while deserializing the index file - #[error("error deserializing index file")] - FileDeser(#[source] serde_yaml::Error), - - /// An unknown error occurred - #[error("unknown error")] - Other(#[source] Box), -} - -/// An error that occurred while creating a package version -#[derive(Debug, Error)] -pub enum CreatePackageVersionError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while getting a package from the index - #[error("error getting a package from the index")] - IndexPackage(#[from] IndexPackageError), - - /// An error that occurred while serializing the index file - #[error("error serializing index file")] - FileSer(#[source] serde_yaml::Error), - - /// An error that occurred while committing and pushing to the index - #[error("error committing and pushing to the index")] - CommitAndPush(#[from] CommitAndPushError), - - /// An error that occurred while interacting with the scope owners - #[error("error interacting with the scope owners")] - ScopeOwners(#[from] ScopeOwnersError), - - /// The scope is missing ownership - #[error("missing scope ownership")] - MissingScopeOwnership, - - /// An error that occurred while converting a manifest to an index file entry - #[error("error converting manifest to index file entry")] - FromManifestIndexFileEntry(#[from] FromManifestIndexFileEntry), -} - -/// An error that occurred while getting the index's configuration -#[derive(Debug, Error)] -pub enum ConfigError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while deserializing the index config - #[error("error deserializing index config")] - ConfigDeser(#[source] serde_yaml::Error), - - /// The index does not have a config file - #[error("index does not have a config file - this is an issue with the index, please contact the maintainer of the index")] - MissingConfig, -} - -fn get_refspec( - repo: &Repository, - remote: &mut Remote, -) -> Result<(String, String), GetRefSpecError> { - let upstream_branch_buf = repo.branch_upstream_name( - repo.head()? - .name() - .ok_or(GetRefSpecError::UpstreamBranchNotFound)?, - )?; - let upstream_branch = upstream_branch_buf - .as_str() - .ok_or(GetRefSpecError::UpstreamBranchNotUtf8)?; - - let refspec_buf = remote - .refspecs() - .find(|r| r.direction() == git2::Direction::Fetch && r.dst_matches(upstream_branch)) - .ok_or(GetRefSpecError::RefSpecNotFound( - upstream_branch.to_string(), - ))? - .rtransform(upstream_branch)?; - let refspec = refspec_buf - .as_str() - .ok_or(GetRefSpecError::RefSpecNotUtf8)?; - - Ok((refspec.to_string(), upstream_branch.to_string())) -} - -macro_rules! remote_callbacks { - ($index:expr) => {{ - #[allow(unused_imports)] - use crate::index::Index; - let mut remote_callbacks = git2::RemoteCallbacks::new(); - - if let Some(credentials) = &$index.credentials_fn() { - let credentials = std::sync::Arc::clone(credentials); - - remote_callbacks.credentials(move |a, b, c| credentials()(a, b, c)); - } - - remote_callbacks - }}; -} -pub(crate) use remote_callbacks; - -impl GitIndex { - /// Creates a new git index. The `refresh` method must be called before using the index, preferably immediately after creating it. - pub fn new>( - path: P, - repo_url: &Url, - credentials: Option, - registry_auth_token: Option, - ) -> Self { - Self { - path: path.as_ref().to_path_buf(), - repo_url: repo_url.clone(), - credentials_fn: credentials.map(Arc::new), - registry_auth_token, - } - } - - /// Gets the path of the index - pub fn path(&self) -> &Path { - &self.path - } - - /// Commits and pushes to the index - pub fn commit_and_push( - &self, - message: &str, - signature: &Signature, - ) -> Result<(), CommitAndPushError> { - let repo = Repository::open(&self.path)?; - - let mut index = repo.index()?; - index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; - index.write()?; - - let oid = index.write_tree()?; - let tree = repo.find_tree(oid)?; - - let parent_commit = repo.head()?.peel_to_commit()?; - - repo.commit( - Some("HEAD"), - signature, - signature, - message, - &tree, - &[&parent_commit], - )?; - - let mut remote = repo.find_remote("origin")?; - - let (refspec, _) = get_refspec(&repo, &mut remote)?; - - remote.push( - &[&refspec], - Some(git2::PushOptions::new().remote_callbacks(remote_callbacks!(self))), - )?; - - Ok(()) - } -} - -macro_rules! refresh_git_based_index { - ($index:expr) => {{ - let repo = if $index.path.exists() { - Repository::open(&$index.path).ok() - } else { - None - }; - - if let Some(repo) = repo { - let mut remote = repo.find_remote("origin")?; - let (refspec, upstream_branch) = get_refspec(&repo, &mut remote)?; - - remote.fetch( - &[&refspec], - Some(git2::FetchOptions::new().remote_callbacks(remote_callbacks!($index))), - None, - )?; - - let commit = repo.find_reference(&upstream_branch)?.peel_to_commit()?; - - debug!( - "refreshing index, fetching {refspec}#{} from origin", - commit.id().to_string() - ); - - repo.reset(&commit.into_object(), git2::ResetType::Hard, None)?; - - Ok(()) - } else { - debug!( - "refreshing index - first time, cloning {} into {}", - $index.repo_url, - $index.path.display() - ); - create_dir_all(&$index.path)?; - - let mut fetch_options = git2::FetchOptions::new(); - fetch_options.remote_callbacks(remote_callbacks!($index)); - - RepoBuilder::new() - .fetch_options(fetch_options) - .clone(&$index.repo_url.to_string(), &$index.path)?; - - Ok(()) - } - }}; -} - -impl Index for GitIndex { - fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError> { - let path = self.path.join(scope).join("owners.yaml"); - - if !path.exists() { - return Ok(None); - } - - let contents = std::fs::read(&path)?; - let owners: ScopeOwners = - serde_yaml::from_slice(&contents).map_err(ScopeOwnersError::ScopeOwnersDeser)?; - - Ok(Some(owners)) - } - - fn create_scope_for( - &mut self, - scope: &str, - owners: &ScopeOwners, - ) -> Result { - let path = self.path.join(scope); - - if path.exists() { - return Ok(false); - } - - create_dir_all(&path)?; - - serde_yaml::to_writer(std::fs::File::create(path.join("owners.yaml"))?, owners) - .map_err(ScopeOwnersError::ScopeOwnersDeser)?; - - Ok(true) - } - - fn package(&self, name: &PackageName) -> Result, IndexPackageError> { - let path = self.path.join(name.scope()).join(name.name()); - - if !path.exists() { - return Ok(None); - } - - let contents = std::fs::read(&path)?; - let file: IndexFile = - serde_yaml::from_slice(&contents).map_err(IndexPackageError::FileDeser)?; - - Ok(Some(file)) - } - - fn create_package_version( - &mut self, - manifest: &Manifest, - uploader: &u64, - ) -> Result, CreatePackageVersionError> { - let scope = manifest.name.scope(); - - if let Some(owners) = self.scope_owners(scope)? { - if !owners.contains(uploader) { - return Err(CreatePackageVersionError::MissingScopeOwnership); - } - } else if !self.create_scope_for(scope, &BTreeSet::from([*uploader]))? { - return Err(CreatePackageVersionError::MissingScopeOwnership); - } - - let path = self.path.join(scope); - - let mut file = - if let Some(file) = self.package(&PackageName::Standard(manifest.name.clone()))? { - if file.iter().any(|e| e.version == manifest.version) { - return Ok(None); - } - file - } else { - BTreeSet::new() - }; - - let entry: IndexFileEntry = manifest.clone().try_into()?; - file.insert(entry.clone()); - - serde_yaml::to_writer( - std::fs::File::create(path.join(manifest.name.name()))?, - &file, - ) - .map_err(CreatePackageVersionError::FileSer)?; - - Ok(Some(entry)) - } - - fn config(&self) -> Result { - let path = self.path.join("config.yaml"); - - if !path.exists() { - return Err(ConfigError::MissingConfig); - } - - let contents = std::fs::read(&path)?; - let config: IndexConfig = - serde_yaml::from_slice(&contents).map_err(ConfigError::ConfigDeser)?; - - Ok(config) - } - - fn credentials_fn(&self) -> Option<&Arc> { - self.credentials_fn.as_ref() - } - - fn url(&self) -> &Url { - &self.repo_url - } - - fn registry_auth_token(&self) -> Option<&str> { - self.registry_auth_token.as_deref() - } - - fn refresh(&self) -> Result<(), RefreshError> { - refresh_git_based_index!(self) - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -/// The configuration of the index -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields)] -pub struct IndexConfig { - /// The URL of the index's API - pub api: Url, - /// The URL of the index's download API, defaults to `{API_URL}/v0/packages/{PACKAGE_AUTHOR}/{PACKAGE_NAME}/{PACKAGE_VERSION}`. - /// Has the following variables: - /// - `{API_URL}`: The URL of the index's API (without trailing `/`) - /// - `{PACKAGE_AUTHOR}`: The author of the package - /// - `{PACKAGE_NAME}`: The name of the package - /// - `{PACKAGE_VERSION}`: The version of the package - pub download: Option, - /// Whether to allow git dependencies - #[serde(default)] - pub git_allowed: bool, - /// Whether to allow custom registries - #[serde(default)] - pub custom_registry_allowed: bool, - /// The OAuth client ID for GitHub OAuth - pub github_oauth_client_id: String, -} - -impl IndexConfig { - /// Gets the URL of the index's API - pub fn api(&self) -> &str { - self.api.as_str().trim_end_matches('/') - } - - /// Gets the URL of the index's download API - pub fn download(&self) -> String { - self.download - .as_ref() - .unwrap_or( - &"{API_URL}/v0/packages/{PACKAGE_AUTHOR}/{PACKAGE_NAME}/{PACKAGE_VERSION}" - .to_string(), - ) - .replace("{API_URL}", self.api()) - } -} - -/// An entry in the index file -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -pub struct IndexFileEntry { - /// The version of the package - pub version: Version, - /// The realm of the package - pub realm: Option, - /// When the package was published - #[serde(default = "Utc::now")] - pub published_at: DateTime, - - /// A description of the package - #[serde(default, skip_serializing_if = "Option::is_none")] - pub description: Option, - - /// The dependencies of the package - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub dependencies: BTreeMap, -} - -/// An error that occurred while converting a manifest to an index file entry -#[derive(Debug, Error)] -pub enum FromManifestIndexFileEntry { - /// An error that occurred because an index is not specified - #[error("index {0} is not specified")] - IndexNotSpecified(String), -} - -impl TryFrom for IndexFileEntry { - type Error = FromManifestIndexFileEntry; - - fn try_from(manifest: Manifest) -> Result { - let dependencies = manifest.dependencies(); - let indices = manifest.indices; - - Ok(Self { - version: manifest.version, - realm: manifest.realm, - published_at: Utc::now(), - - description: manifest.description, - - dependencies: dependencies - .into_iter() - .map(|(desired_name, (dep, ty))| { - Ok(( - desired_name, - match dep { - DependencySpecifier::Registry(mut registry) => { - registry.index = indices - .get(®istry.index) - .ok_or_else(|| { - FromManifestIndexFileEntry::IndexNotSpecified( - registry.index.clone(), - ) - })? - .clone(); - (DependencySpecifier::Registry(registry), ty) - } - d => (d, ty), - }, - )) - }) - .collect::>()?, - }) - } -} - -impl PartialOrd for IndexFileEntry { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.version.cmp(&other.version)) - } -} - -impl Ord for IndexFileEntry { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.version.cmp(&other.version) - } -} - -/// An index file -pub type IndexFile = BTreeSet; - -#[cfg(feature = "wally")] -#[derive(Clone)] -pub(crate) struct WallyIndex { - repo_url: Url, - registry_auth_token: Option, - credentials_fn: Option>, - pub(crate) path: PathBuf, -} - -#[cfg(feature = "wally")] -impl Debug for WallyIndex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("WallyIndex") - .field("path", &self.path) - .field("repo_url", &self.repo_url) - .finish() - } -} - -#[cfg(feature = "wally")] -impl WallyIndex { - pub(crate) fn new( - repo_url: Url, - registry_auth_token: Option, - path: &Path, - credentials_fn: Option>, - ) -> Self { - Self { - repo_url, - registry_auth_token, - path: path.to_path_buf(), - credentials_fn, - } - } -} - -#[cfg(feature = "wally")] -impl Index for WallyIndex { - fn scope_owners(&self, _scope: &str) -> Result, ScopeOwnersError> { - unimplemented!("wally index is a virtual index meant for wally compatibility only") - } - - fn create_scope_for( - &mut self, - _scope: &str, - _owners: &ScopeOwners, - ) -> Result { - unimplemented!("wally index is a virtual index meant for wally compatibility only") - } - - fn package(&self, name: &PackageName) -> Result, IndexPackageError> { - let path = self.path.join(name.scope()).join(name.name()); - - if !path.exists() { - return Ok(None); - } - - let file = std::fs::File::open(&path)?; - let file = std::io::BufReader::new(file); - - let manifest_stream = serde_json::Deserializer::from_reader(file) - .into_iter::() - .collect::, _>>() - .map_err(|e| IndexPackageError::Other(Box::new(e)))?; - - Ok(Some( - manifest_stream - .into_iter() - .map(|m| m.try_into()) - .collect::, _>>() - .map_err(|e| IndexPackageError::Other(Box::new(e)))?, - )) - } - - fn create_package_version( - &mut self, - _manifest: &Manifest, - _uploader: &u64, - ) -> Result, CreatePackageVersionError> { - unimplemented!("wally index is a virtual index meant for wally compatibility only") - } - - fn config(&self) -> Result { - unimplemented!("wally index is a virtual index meant for wally compatibility only") - } - - fn credentials_fn(&self) -> Option<&Arc> { - self.credentials_fn.as_ref() - } - - fn url(&self) -> &Url { - &self.repo_url - } - - fn registry_auth_token(&self) -> Option<&str> { - self.registry_auth_token.as_deref() - } - - fn refresh(&self) -> Result<(), RefreshError> { - refresh_git_based_index!(self) - } - - fn as_any(&self) -> &dyn Any { - self - } -} diff --git a/src/lib.rs b/src/lib.rs index 9db2de4..4875efd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,51 +1,160 @@ -#![deny(missing_docs)] -//! pesde is a package manager for Roblox that is designed to be feature-rich and easy to use. -//! Currently, pesde is in a very early stage of development, but already supports the following features: -//! - Managing dependencies -//! - Re-exporting types -//! - `bin` exports (ran with Lune) -//! - Patching packages -//! - Downloading packages from Wally registries +// #![deny(missing_docs)] - TODO: bring this back before publishing 0.5 -/// Resolving, downloading and managing dependencies -pub mod dependencies; -/// Managing the pesde index -pub mod index; -/// Creating linking files ('re-export' modules) -pub mod linking_file; -/// Managing the pesde manifest +#[cfg(not(any(feature = "roblox", feature = "lune", feature = "luau")))] +compile_error!("at least one of the features `roblox`, `lune`, or `luau` must be enabled"); + +use once_cell::sync::Lazy; +use std::path::{Path, PathBuf}; + +pub mod lockfile; pub mod manifest; -/// Multi-threading utilities -pub mod multithread; -/// Creating, parsing, and validating package names -pub mod package_name; -/// Managing patches -pub mod patches; -/// Managing pesde projects -pub mod project; +pub mod names; +pub mod source; -/// The folder that contains shared packages -pub const PACKAGES_FOLDER: &str = "packages"; -/// The folder that contains dev packages -pub const DEV_PACKAGES_FOLDER: &str = "dev_packages"; -/// The folder that contains server packages -pub const SERVER_PACKAGES_FOLDER: &str = "server_packages"; -/// The folder that contains the packages index (where every package is stored after being downloaded) -pub const INDEX_FOLDER: &str = "pesde_index"; -/// The name of the manifest file pub const MANIFEST_FILE_NAME: &str = "pesde.yaml"; -/// The name of the lockfile -pub const LOCKFILE_FILE_NAME: &str = "pesde-lock.yaml"; -/// The name of the patches folder -pub const PATCHES_FOLDER: &str = "patches"; -/// Files to be ignored when publishing -pub const IGNORED_FOLDERS: &[&str] = &[ - PACKAGES_FOLDER, - DEV_PACKAGES_FOLDER, - SERVER_PACKAGES_FOLDER, - ".git", -]; +pub const LOCKFILE_FILE_NAME: &str = "pesde.lock"; -pub(crate) fn is_default(t: &T) -> bool { - t == &Default::default() +pub(crate) static REQWEST_CLIENT: Lazy = Lazy::new(|| { + reqwest::blocking::Client::builder() + .user_agent(concat!( + env!("CARGO_PKG_NAME"), + "/", + env!("CARGO_PKG_VERSION") + )) + .build() + .expect("failed to create reqwest client") +}); + +#[derive(Debug, Clone)] +pub struct GitAccount { + username: String, + password: secrecy::SecretString, +} + +impl GitAccount { + pub fn new>(username: String, password: S) -> Self { + GitAccount { + username, + password: password.into(), + } + } + + pub fn as_account(&self) -> gix::sec::identity::Account { + use secrecy::ExposeSecret; + + gix::sec::identity::Account { + username: self.username.clone(), + password: self.password.expose_secret().to_string(), + } + } +} + +impl From for GitAccount { + fn from(account: gix::sec::identity::Account) -> Self { + GitAccount { + username: account.username, + password: account.password.into(), + } + } +} + +#[derive(Debug, Default, Clone)] +pub struct AuthConfig { + pesde_token: Option, + git_credentials: Option, +} + +impl AuthConfig { + pub fn new() -> Self { + AuthConfig::default() + } + + pub fn with_pesde_token>(mut self, token: Option) -> Self { + self.pesde_token = token.map(Into::into); + self + } + + pub fn with_git_credentials(mut self, git_credentials: Option) -> Self { + self.git_credentials = git_credentials; + self + } +} + +pub(crate) fn authenticate_conn( + conn: &mut gix::remote::Connection< + '_, + '_, + Box, + >, + auth_config: AuthConfig, +) { + if let Some(iden) = auth_config.git_credentials { + conn.set_credentials(move |action| match action { + gix::credentials::helper::Action::Get(ctx) => { + Ok(Some(gix::credentials::protocol::Outcome { + identity: iden.as_account(), + next: gix::credentials::helper::NextAction::from(ctx), + })) + } + gix::credentials::helper::Action::Store(_) => Ok(None), + gix::credentials::helper::Action::Erase(_) => Ok(None), + }); + } +} + +#[derive(Debug)] +pub struct Project { + path: PathBuf, + data_dir: PathBuf, + auth_config: AuthConfig, +} + +impl Project { + pub fn new, Q: AsRef>( + path: P, + data_dir: Q, + auth_config: AuthConfig, + ) -> Self { + Project { + path: path.as_ref().to_path_buf(), + data_dir: data_dir.as_ref().to_path_buf(), + auth_config, + } + } + + pub fn path(&self) -> &Path { + &self.path + } + + pub fn data_dir(&self) -> &Path { + &self.data_dir + } + + pub fn read_manifest(&self) -> Result, errors::ManifestReadError> { + let bytes = std::fs::read(self.path.join(MANIFEST_FILE_NAME))?; + Ok(bytes) + } + + pub fn deser_manifest(&self) -> Result { + let bytes = std::fs::read(self.path.join(MANIFEST_FILE_NAME))?; + Ok(serde_yaml::from_slice(&bytes)?) + } + + pub fn write_manifest>(&self, manifest: S) -> Result<(), std::io::Error> { + std::fs::write(self.path.join(MANIFEST_FILE_NAME), manifest.as_ref()) + } +} + +pub mod errors { + use thiserror::Error; + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum ManifestReadError { + #[error("io error reading manifest file")] + Io(#[from] std::io::Error), + + #[error("error deserializing manifest file")] + Serde(#[from] serde_yaml::Error), + } } diff --git a/src/linking_file.rs b/src/linking_file.rs deleted file mode 100644 index dd6b330..0000000 --- a/src/linking_file.rs +++ /dev/null @@ -1,317 +0,0 @@ -use std::{ - collections::HashSet, - fs::{create_dir_all, read_to_string, write}, - path::{Component, Path, PathBuf}, -}; - -use full_moon::{ - ast::types::ExportedTypeDeclaration, - parse, - visitors::{Visit, Visitor}, -}; -use log::debug; -use semver::Version; -use thiserror::Error; - -use crate::{ - dependencies::resolution::{packages_folder, ResolvedPackage, RootLockfileNode}, - manifest::{Manifest, ManifestReadError, PathStyle, Realm}, - package_name::PackageName, - project::Project, -}; - -struct TypeVisitor { - pub(crate) types: Vec, -} - -impl Visitor for TypeVisitor { - fn visit_exported_type_declaration(&mut self, node: &ExportedTypeDeclaration) { - let name = node.type_declaration().type_name().to_string(); - - let (declaration_generics, generics) = - if let Some(declaration) = node.type_declaration().generics() { - let mut declaration_generics = vec![]; - let mut generics = vec![]; - - for generic in declaration.generics().iter() { - declaration_generics.push(generic.to_string()); - - if generic.default_type().is_some() { - generics.push(generic.parameter().to_string()) - } else { - generics.push(generic.to_string()) - } - } - - ( - format!("<{}>", declaration_generics.join(", ")), - format!("<{}>", generics.join(", ")), - ) - } else { - ("".to_string(), "".to_string()) - }; - - self.types.push(format!( - "export type {name}{declaration_generics} = module.{name}{generics}\n" - )); - } -} - -/// Generates the contents of a linking file, given the require path, and the contents of the target file -/// The contents will be scanned for type exports, and the linking file will be generated accordingly -pub fn linking_file(content: &str, path: &str) -> Result { - let mut linker = format!("local module = require({path})\n"); - let mut visitor = TypeVisitor { types: vec![] }; - - parse(content)?.nodes().visit(&mut visitor); - - for ty in visitor.types { - linker.push_str(&ty); - } - - linker.push_str("return module"); - - Ok(linker) -} - -#[derive(Debug, Error)] -/// An error that occurred while linking dependencies -pub enum LinkingError { - #[error("error interacting with the file system")] - /// An error that occurred while interacting with the file system - Io(#[from] std::io::Error), - - #[error("failed getting file name from {0}")] - /// An error that occurred while getting a file name - FileNameFail(PathBuf), - - #[error("failed converting file name to string")] - /// An error that occurred while converting a file name to a string - FileNameToStringFail, - - #[error("failed getting relative path from {0} to {1}")] - /// An error that occurred while getting a relative path - RelativePathFail(PathBuf, PathBuf), - - #[error("failed getting path parent of {0}")] - /// An error that occurred while getting a path parent - ParentFail(PathBuf), - - #[error("failed to convert path component to string")] - /// An error that occurred while converting a path component to a string - ComponentToStringFail, - - #[error("failed to get path string")] - /// An error that occurred while getting a path string - PathToStringFail, - - #[error("error encoding utf-8 string")] - /// An error that occurred while converting a byte slice to a string - Utf8(#[from] std::str::Utf8Error), - - #[error("error reading manifest")] - /// An error that occurred while reading the manifest of a package - ManifestRead(#[from] ManifestReadError), - - #[error("missing realm {0} in-game path")] - /// An error that occurred while getting the in-game path for a realm - MissingRealmInGamePath(Realm), - - #[error("library source is not valid Luau")] - /// An error that occurred because the library source is not valid Luau - InvalidLuau(#[from] full_moon::Error), -} - -pub(crate) fn link, Q: AsRef>( - project: &Project, - resolved_pkg: &ResolvedPackage, - lockfile: &RootLockfileNode, - destination_dir: P, - parent_dependency_packages_dir: Q, - desired_name: &str, - as_root: bool, -) -> Result<(), LinkingError> { - let (_, source_dir) = resolved_pkg.directory(project.path()); - let file = Manifest::from_path(&source_dir)?; - - let Some(relative_lib_export) = file.exports.lib else { - return Ok(()); - }; - - let lib_export = relative_lib_export.to_path(&source_dir); - - let path_style = &project.manifest().path_style; - let PathStyle::Roblox { place } = &path_style; - - debug!("linking {resolved_pkg} using `{}` path style", path_style); - - let pkg_name = resolved_pkg.pkg_ref.name(); - let name = pkg_name.name(); - - let destination_dir = match lockfile - .specifiers - .get(&pkg_name) - .and_then(|v| v.get(resolved_pkg.pkg_ref.version())) - { - Some((specifier, _)) if as_root => project.path().join(packages_folder( - specifier.realm().copied().unwrap_or_default(), - )), - _ => destination_dir.as_ref().to_path_buf(), - }; - create_dir_all(&destination_dir)?; - let destination_file = destination_dir.join(desired_name.to_string() + ".lua"); - - let realm_folder = project.path().join(resolved_pkg.packages_folder()); - let in_different_folders = realm_folder != parent_dependency_packages_dir.as_ref(); - - let mut path = if in_different_folders { - pathdiff::diff_paths(&source_dir, &realm_folder) - .ok_or_else(|| LinkingError::RelativePathFail(source_dir.clone(), realm_folder))? - } else { - pathdiff::diff_paths(&source_dir, &destination_dir).ok_or_else(|| { - LinkingError::RelativePathFail(source_dir.clone(), destination_dir.to_path_buf()) - })? - }; - path.set_extension(""); - - let beginning = if in_different_folders { - place - .get(&resolved_pkg.realm) - .ok_or_else(|| LinkingError::MissingRealmInGamePath(resolved_pkg.realm))? - .clone() - } else if name == "init" { - "script".to_string() - } else { - "script.Parent".to_string() - }; - - let mut components = path - .components() - .map(|component| { - Ok(match component { - Component::ParentDir => ".Parent".to_string(), - Component::Normal(part) => format!( - "[{:?}]", - part.to_str().ok_or(LinkingError::ComponentToStringFail)? - ), - _ => unreachable!("invalid path component"), - }) - }) - .collect::, LinkingError>>()?; - components.pop(); - - let path = beginning + &components.join("") + &format!("[{name:?}]"); - - debug!( - "writing linking file for {} with import `{path}` to {}", - source_dir.display(), - destination_file.display() - ); - - let file_contents = match relative_lib_export.as_str() { - "true" => "".to_string(), - _ => read_to_string(lib_export)?, - }; - - let linking_file_contents = linking_file(&file_contents, &path)?; - - write(&destination_file, linking_file_contents)?; - - Ok(()) -} - -#[derive(Debug, Error)] -#[error("error linking {1}@{2} to {3}@{4}")] -/// An error that occurred while linking the dependencies -pub struct LinkingDependenciesError( - #[source] LinkingError, - PackageName, - Version, - PackageName, - Version, -); - -impl Project { - /// Links the dependencies of the project - pub fn link_dependencies( - &self, - lockfile: &RootLockfileNode, - ) -> Result<(), LinkingDependenciesError> { - let root_deps = lockfile - .specifiers - .iter() - .flat_map(|(name, versions)| versions.keys().map(|version| (name.clone(), version))) - .collect::>(); - - for (name, versions) in &lockfile.children { - for (version, resolved_pkg) in versions { - let (container_dir, _) = resolved_pkg.directory(self.path()); - - debug!( - "linking package {name}@{version}'s dependencies to directory {}", - container_dir.display() - ); - - for (dep_name, (dep_version, desired_name)) in &resolved_pkg.dependencies { - let dep = lockfile - .children - .get(dep_name) - .and_then(|versions| versions.get(dep_version)) - .unwrap(); - - link( - self, - dep, - lockfile, - &container_dir, - &self.path().join(resolved_pkg.packages_folder()), - desired_name, - false, - ) - .map_err(|e| { - LinkingDependenciesError( - e, - dep_name.clone(), - dep_version.clone(), - name.clone(), - version.clone(), - ) - })?; - } - - if root_deps.contains(&(name.clone(), version)) { - let (specifier, desired_name) = lockfile.root_specifier(resolved_pkg).unwrap(); - let linking_dir = &self.path().join(packages_folder( - specifier.realm().copied().unwrap_or_default(), - )); - - debug!( - "linking root package {name}@{version} to directory {}", - linking_dir.display() - ); - - link( - self, - resolved_pkg, - lockfile, - linking_dir, - self.path().join(resolved_pkg.packages_folder()), - desired_name, - true, - ) - .map_err(|e| { - LinkingDependenciesError( - e, - name.clone(), - version.clone(), - name.clone(), - version.clone(), - ) - })?; - } - } - } - - Ok(()) - } -} diff --git a/src/lockfile.rs b/src/lockfile.rs new file mode 100644 index 0000000..126867a --- /dev/null +++ b/src/lockfile.rs @@ -0,0 +1,20 @@ +use crate::{ + names::{PackageName, PackageNames}, + source::{DependencySpecifiers, PackageRefs}, +}; +use semver::Version; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Lockfile { + pub name: PackageName, + + pub specifiers: BTreeMap>, + pub dependencies: BTreeMap>, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LockfileNode { + pub pkg_ref: PackageRefs, +} diff --git a/src/main.rs b/src/main.rs index 48aca38..75253ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,48 @@ -use once_cell::sync::Lazy; - -use cli::{auth::auth_command, config::config_command, root::root_command}; - -use crate::cli::{CliConfig, Command, CLI, MULTI}; +use crate::cli::get_token; +use clap::Parser; +use colored::Colorize; +use pesde::{AuthConfig, Project}; mod cli; -fn main() -> anyhow::Result<()> { - Lazy::force(&MULTI); +#[derive(Parser, Debug)] +#[clap(version, about = "pesde is a feature-rich package manager for Luau")] +#[command(disable_version_flag = true)] +struct Cli { + /// Print version + #[arg(short = 'v', short_alias = 'V', long, action = clap::builder::ArgAction::Version)] + version: (), - match CLI.command.clone() { - Command::Auth { command } => auth_command(command), - Command::Config { command } => config_command(command), - cmd => root_command(cmd), + #[command(subcommand)] + subcommand: cli::SubCommand, +} + +fn main() { + let project_dirs = + directories::ProjectDirs::from("com", env!("CARGO_PKG_NAME"), env!("CARGO_BIN_NAME")) + .expect("couldn't get home directory"); + let cwd = std::env::current_dir().expect("failed to get current working directory"); + let cli = Cli::parse(); + + let data_dir = project_dirs.data_dir(); + + if let Err(err) = get_token(data_dir).and_then(|token| { + cli.subcommand.run(Project::new( + cwd, + data_dir, + AuthConfig::new().with_pesde_token(token), + )) + }) { + eprintln!("{}: {}\n", "error".red().bold(), err.to_string().bold()); + + let cause = err.chain().skip(1).collect::>(); + + if !cause.is_empty() { + eprintln!("{}:", "caused by".red().bold()); + for err in cause { + eprintln!(" - {}", err.to_string().bold()); + } + } + std::process::exit(1); } } diff --git a/src/manifest.rs b/src/manifest.rs index 8f8f76b..520413a 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -1,415 +1,174 @@ -use std::{collections::BTreeMap, fmt::Display, fs::read, path::Path, str::FromStr}; - -use cfg_if::cfg_if; +use crate::{names::PackageName, source::DependencySpecifiers}; use relative_path::RelativePathBuf; use semver::Version; -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -use crate::{ - dependencies::DependencySpecifier, package_name::StandardPackageName, MANIFEST_FILE_NAME, +use serde::{de::Visitor, Deserialize, Deserializer, Serialize}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; +use std::{ + collections::BTreeMap, + fmt::{Display, Formatter}, + str::FromStr, }; -/// The files exported by the package #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(deny_unknown_fields)] pub struct Exports { - /// Points to the file which exports the package. As of currently this is only used for re-exporting types. - /// Libraries must have a structure in Roblox where the main file becomes the folder, for example: - /// A package called pesde/lib has a file called src/main.lua. - /// pesde puts this package in a folder called pesde_lib. - /// The package has to have set up configuration for file-syncing tools such as Rojo so that src/main.lua becomes the pesde_lib and turns it into a ModuleScript #[serde(default, skip_serializing_if = "Option::is_none")] pub lib: Option, - /// Points to the file that will be executed with Lune #[serde(default, skip_serializing_if = "Option::is_none")] pub bin: Option, } -/// The path style used by the package -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[serde(rename_all = "snake_case", deny_unknown_fields)] -pub enum PathStyle { - /// The path style used by Roblox (e.g. `script.Parent` or `script.Parent.Parent`) - Roblox { - /// A map of realm to in-game package folder location (used for linking between packages in different realms) - #[serde(default)] - place: BTreeMap, - }, +pub enum Target { + #[cfg(feature = "roblox")] + Roblox, + #[cfg(feature = "lune")] + Lune, + #[cfg(feature = "luau")] + Luau, } -impl Default for PathStyle { - fn default() -> Self { - PathStyle::Roblox { - place: BTreeMap::new(), - } - } -} - -impl Display for PathStyle { +impl Display for Target { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - PathStyle::Roblox { .. } => write!(f, "roblox"), + #[cfg(feature = "roblox")] + Target::Roblox => write!(f, "roblox"), + #[cfg(feature = "lune")] + Target::Lune => write!(f, "lune"), + #[cfg(feature = "luau")] + Target::Luau => write!(f, "luau"), + } + } +} + +impl Target { + // self is the project's target, dependency is the target of the dependency + fn is_compatible_with(&self, dependency: &Self) -> bool { + if self == dependency { + return true; + } + + match (self, dependency) { + #[cfg(all(feature = "lune", feature = "luau"))] + (Target::Lune, Target::Luau) => true, + + _ => false, } } } -/// The realm of the package #[derive( - Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Default, + Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, )] -#[serde(rename_all = "snake_case", deny_unknown_fields)] -pub enum Realm { - /// The package is shared (usually ReplicatedStorage) - #[default] - Shared, - /// The package is server only (usually ServerScriptService/ServerStorage) - Server, - /// The package is development only - Development, -} - -impl Realm { - /// Returns the most restrictive realm - pub fn or(self, other: Self) -> Self { - match self { - Realm::Shared => other, - _ => self, - } - } -} - -impl Display for Realm { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Realm::Shared => write!(f, "shared"), - Realm::Server => write!(f, "server"), - Realm::Development => write!(f, "development"), - } - } -} - -/// An error that occurred while parsing a realm from a string -#[derive(Debug, Error)] -#[error("invalid realm {0}")] -pub struct FromStrRealmError(String); - -impl FromStr for Realm { - type Err = FromStrRealmError; - - fn from_str(s: &str) -> Result { - match s { - "shared" => Ok(Realm::Shared), - "server" => Ok(Realm::Server), - "development" => Ok(Realm::Development), - _ => Err(FromStrRealmError(s.to_string())), - } - } -} - -/// A key to override dependencies -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct OverrideKey(pub Vec>); -impl Serialize for OverrideKey { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str( - &self - .0 +impl FromStr for OverrideKey { + type Err = errors::OverrideKeyFromStr; + + fn from_str(s: &str) -> Result { + Ok(Self( + s.split(',') + .map(|overrides| overrides.split('>').map(|s| s.to_string()).collect()) + .collect(), + )) + } +} + +impl Display for OverrideKey { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + self.0 .iter() .map(|overrides| { overrides .iter() - .map(String::to_string) + .map(|o| o.as_str()) .collect::>() .join(">") }) .collect::>() - .join(","), + .join(",") ) } } -impl<'de> Deserialize<'de> for OverrideKey { - fn deserialize>(deserializer: D) -> Result { - let s = String::deserialize(deserializer)?; - let mut key = Vec::new(); - for overrides in s.split(',') { - key.push( - overrides - .split('>') - .map(|s| String::from_str(s).map_err(serde::de::Error::custom)) - .collect::, _>>()?, - ); +fn deserialize_dep_specs<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + struct SpecsVisitor; + + impl<'de> Visitor<'de> for SpecsVisitor { + type Value = BTreeMap; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a map of dependency specifiers") } - Ok(OverrideKey(key)) + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut specs = BTreeMap::new(); + + while let Some((key, mut value)) = map.next_entry::()? { + value.set_alias(key.to_string()); + specs.insert(key, value); + } + + Ok(specs) + } } + + deserializer.deserialize_map(SpecsVisitor) } -/// The manifest of a package #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Manifest { - /// The name of the package - pub name: StandardPackageName, - /// The version of the package. Must be [semver](https://semver.org) compatible. The registry will not accept non-semver versions and the CLI will not handle such packages + pub name: PackageName, pub version: Version, - /// A short description of the package - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] pub description: Option, - /// The license of the package - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] pub license: Option, - /// The authors of the package - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] pub authors: Option>, - /// The repository of the package - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] pub repository: Option, - /// The files exported by the package #[serde(default)] pub exports: Exports, - /// The path style to use for linking modules - #[serde(default)] - pub path_style: PathStyle, - /// Whether the package is private (it should not be published) + pub target: Target, #[serde(default)] pub private: bool, - /// The realm of the package - #[serde(default, skip_serializing_if = "Option::is_none")] - pub realm: Option, - /// Indices of the package - pub indices: BTreeMap, - /// The command to generate a `sourcemap.json` + #[serde(default)] + pub indices: BTreeMap, #[cfg(feature = "wally")] - #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub wally_indices: BTreeMap, + #[cfg(feature = "wally")] + #[serde(default)] pub sourcemap_generator: Option, - /// Dependency overrides - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub overrides: BTreeMap, + #[serde(default)] + pub overrides: BTreeMap, - /// The dependencies of the package - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub dependencies: BTreeMap, - /// The peer dependencies of the package - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub peer_dependencies: BTreeMap, + #[serde(default, deserialize_with = "deserialize_dep_specs")] + pub dependencies: BTreeMap, + #[serde(default, deserialize_with = "deserialize_dep_specs")] + pub peer_dependencies: BTreeMap, + #[serde(default, deserialize_with = "deserialize_dep_specs")] + pub dev_dependencies: BTreeMap, } -/// An error that occurred while reading the manifest -#[derive(Debug, Error)] -pub enum ManifestReadError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), +pub mod errors { + use thiserror::Error; - /// An error that occurred while deserializing the manifest - #[error("error deserializing manifest")] - ManifestDeser(#[source] serde_yaml::Error), -} - -cfg_if! { - if #[cfg(feature = "wally")] { - /// An error that occurred while converting the manifest - #[derive(Debug, Error)] - pub enum ManifestConvertError { - /// An error that occurred while reading the manifest - #[error("error reading the manifest")] - ManifestRead(#[from] ManifestReadError), - - /// An error that occurred while converting the manifest - #[error("error converting the manifest")] - ManifestConvert(#[source] toml::de::Error), - - /// The given path does not have a parent - #[error("the path {0} does not have a parent")] - NoParent(std::path::PathBuf), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while writing the manifest - #[error("error writing the manifest")] - ManifestWrite(#[from] crate::manifest::ManifestWriteError), - - /// An error that occurred while parsing the dependencies - #[error("error parsing the dependencies")] - DependencyParse(#[from] crate::dependencies::wally::WallyManifestDependencyError), - } - } else { - /// An error that occurred while converting the manifest - pub type ManifestConvertError = ManifestReadError; - } -} - -/// An error that occurred while writing the manifest -#[derive(Debug, Error)] -pub enum ManifestWriteError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while serializing the manifest - #[error("error serializing manifest")] - ManifestSer(#[from] serde_yaml::Error), -} - -/// The type of dependency -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] -#[serde(rename_all = "snake_case")] -pub enum DependencyType { - /// A normal dependency - #[default] - Normal, - /// A peer dependency - Peer, -} - -pub(crate) fn update_sync_tool_files(project_path: &Path, name: String) -> std::io::Result<()> { - if let Ok(file) = std::fs::File::open(project_path.join("default.project.json")) { - let mut project: serde_json::Value = serde_json::from_reader(file)?; - - if project["name"].as_str() == Some(&name) { - return Ok(()); - } - - project["name"] = serde_json::Value::String(name); - - serde_json::to_writer_pretty( - std::fs::File::create(project_path.join("default.project.json"))?, - &project, - )?; - } - - Ok(()) -} - -impl Manifest { - /// Reads a manifest from a path (if the path is a directory, it will look for the manifest file inside it, otherwise it will read the file directly) - pub fn from_path>(path: P) -> Result { - let path = path.as_ref(); - let path = if path.file_name() == Some(MANIFEST_FILE_NAME.as_ref()) { - path.to_path_buf() - } else { - path.join(MANIFEST_FILE_NAME) - }; - - let raw_contents = read(path)?; - let manifest = - serde_yaml::from_slice(&raw_contents).map_err(ManifestReadError::ManifestDeser)?; - - Ok(manifest) - } - - /// Tries to read the manifest from the given path, and if it fails, tries converting the `wally.toml` and writes a `pesde.yaml` in the same directory - #[cfg(feature = "wally")] - pub fn from_path_or_convert>( - path: P, - ) -> Result { - let dir_path = if path.as_ref().file_name() == Some(MANIFEST_FILE_NAME.as_ref()) { - path.as_ref() - .parent() - .ok_or_else(|| ManifestConvertError::NoParent(path.as_ref().to_path_buf()))? - .to_path_buf() - } else { - path.as_ref().to_path_buf() - }; - - Self::from_path(path).or_else(|_| { - let toml_path = dir_path.join("wally.toml"); - let toml_contents = std::fs::read_to_string(toml_path)?; - let wally_manifest: crate::dependencies::wally::WallyManifest = - toml::from_str(&toml_contents).map_err(ManifestConvertError::ManifestConvert)?; - - let dependencies = - crate::dependencies::wally::parse_wally_dependencies(wally_manifest.clone())?; - - let mut place = BTreeMap::new(); - - if let Some(shared) = wally_manifest.place.shared_packages { - if !shared.is_empty() { - place.insert(Realm::Shared, shared); - } - } - - if let Some(server) = wally_manifest.place.server_packages { - if !server.is_empty() { - place.insert(Realm::Server, server); - } - } - - let manifest = Self { - name: wally_manifest.package.name.clone().into(), - version: wally_manifest.package.version, - exports: Exports { - lib: Some(RelativePathBuf::from("true")), - bin: None, - }, - path_style: PathStyle::Roblox { place }, - private: wally_manifest.package.private.unwrap_or(false), - realm: wally_manifest.package.realm, - indices: BTreeMap::from([( - crate::project::DEFAULT_INDEX_NAME.to_string(), - "".to_string(), - )]), - sourcemap_generator: None, - overrides: BTreeMap::new(), - - dependencies, - peer_dependencies: Default::default(), - description: wally_manifest.package.description, - license: wally_manifest.package.license, - authors: wally_manifest.package.authors, - repository: None, - }; - - manifest.write(&dir_path)?; - - update_sync_tool_files(&dir_path, wally_manifest.package.name.name().to_string())?; - - Ok(manifest) - }) - } - - /// Same as `from_path`, enable the `wally` feature to add support for converting `wally.toml` to `pesde.yaml` - #[cfg(not(feature = "wally"))] - pub fn from_path_or_convert>( - path: P, - ) -> Result { - Self::from_path(path) - } - - /// Returns all dependencies - pub fn dependencies(&self) -> BTreeMap { - self.dependencies - .iter() - .map(|(desired_name, specifier)| { - ( - desired_name.clone(), - (specifier.clone(), DependencyType::Normal), - ) - }) - .chain( - self.peer_dependencies - .iter() - .map(|(desired_name, specifier)| { - ( - desired_name.clone(), - (specifier.clone(), DependencyType::Peer), - ) - }), - ) - .collect() - } - - /// Writes the manifest to a path - pub fn write>(&self, to: P) -> Result<(), ManifestWriteError> { - let manifest_path = to.as_ref().join(MANIFEST_FILE_NAME); - - serde_yaml::to_writer(std::fs::File::create(manifest_path)?, self)?; - - Ok(()) - } + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum OverrideKeyFromStr {} } diff --git a/src/multithread.rs b/src/multithread.rs deleted file mode 100644 index 1ab75c3..0000000 --- a/src/multithread.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::sync::mpsc::{Receiver, Sender}; -use threadpool::ThreadPool; - -/// A multithreaded job -pub struct MultithreadedJob { - progress: Receiver>, - pool: ThreadPool, -} - -impl MultithreadedJob { - /// Creates a new multithreaded job - pub fn new() -> (Self, Sender>) { - let (tx, rx) = std::sync::mpsc::channel(); - let pool = ThreadPool::new(6); - - (Self { progress: rx, pool }, tx) - } - - /// Returns the progress of the job - pub fn progress(&self) -> &Receiver> { - &self.progress - } - - /// Waits for the job to finish - pub fn wait(self) -> Result<(), E> { - self.pool.join(); - - for result in self.progress { - result?; - } - - Ok(()) - } - - /// Executes a function on the thread pool - pub fn execute(&self, tx: &Sender>, f: F) - where - F: (FnOnce() -> Result<(), E>) + Send + 'static, - { - let sender = tx.clone(); - - self.pool.execute(move || { - let result = f(); - sender.send(result).unwrap(); - }); - } -} diff --git a/src/names.rs b/src/names.rs new file mode 100644 index 0000000..df2bfa3 --- /dev/null +++ b/src/names.rs @@ -0,0 +1,95 @@ +use std::{fmt::Display, str::FromStr}; + +use serde::{Deserialize, Serialize}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; + +#[derive(Debug)] +pub enum ErrorReason { + Scope, + Name, +} + +impl Display for ErrorReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorReason::Scope => write!(f, "scope"), + ErrorReason::Name => write!(f, "name"), + } + } +} + +#[derive( + Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, +)] +pub struct PackageName(String, String); + +impl FromStr for PackageName { + type Err = errors::PackageNameError; + + fn from_str(s: &str) -> Result { + let (scope, name) = s + .split_once('/') + .ok_or(Self::Err::InvalidFormat(s.to_string()))?; + + for (reason, part) in [(ErrorReason::Scope, scope), (ErrorReason::Name, name)] { + if part.len() < 3 || part.len() > 32 { + return Err(Self::Err::InvalidLength(reason, part.to_string())); + } + + if part.chars().all(|c| c.is_ascii_digit()) { + return Err(Self::Err::OnlyDigits(reason, part.to_string())); + } + + if part.starts_with('_') || part.ends_with('_') { + return Err(Self::Err::PrePostfixUnderscore(reason, part.to_string())); + } + + if !part.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { + return Err(Self::Err::InvalidCharacters(reason, part.to_string())); + } + } + + Ok(Self(scope.to_string(), name.to_string())) + } +} + +impl Display for PackageName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}/{}", self.0, self.1) + } +} + +impl PackageName { + pub fn as_str(&self) -> (&str, &str) { + (&self.0, &self.1) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum PackageNames { + Pesde(PackageName), +} + +pub mod errors { + use thiserror::Error; + + use crate::names::ErrorReason; + + #[derive(Debug, Error)] + pub enum PackageNameError { + #[error("package name `{0}` is not in the format `scope/name`")] + InvalidFormat(String), + + #[error("package {0} `{1}` contains characters outside a-z, 0-9, and _")] + InvalidCharacters(ErrorReason, String), + + #[error("package {0} `{1}` contains only digits")] + OnlyDigits(ErrorReason, String), + + #[error("package {0} `{1}` starts or ends with an underscore")] + PrePostfixUnderscore(ErrorReason, String), + + #[error("package {0} `{1}` is not within 3-32 characters long")] + InvalidLength(ErrorReason, String), + } +} diff --git a/src/package_name.rs b/src/package_name.rs deleted file mode 100644 index 61e2715..0000000 --- a/src/package_name.rs +++ /dev/null @@ -1,423 +0,0 @@ -use std::{ - fmt::Debug, - hash::Hash, - {fmt::Display, str::FromStr}, -}; - -use cfg_if::cfg_if; -use serde::{ - de::{IntoDeserializer, Visitor}, - Deserialize, Serialize, -}; -use thiserror::Error; - -/// A package name -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct StandardPackageName(String, String); - -/// An error that occurred while validating a package name part (scope or name) -#[derive(Debug, Error)] -pub enum StandardPackageNameValidationError { - /// The package name part is empty - #[error("package name part cannot be empty")] - EmptyPart, - /// The package name part contains invalid characters (only lowercase ASCII characters, numbers, and underscores are allowed) - #[error("package name {0} part can only contain lowercase ASCII characters, numbers, and underscores")] - InvalidPart(String), - /// The package name part is too long (it cannot be longer than 24 characters) - #[error("package name {0} part cannot be longer than 24 characters")] - PartTooLong(String), -} - -/// Validates a package name part (scope or name) -pub fn validate_part(part: &str) -> Result<(), StandardPackageNameValidationError> { - if part.is_empty() { - return Err(StandardPackageNameValidationError::EmptyPart); - } - - if !part - .chars() - .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_') - { - return Err(StandardPackageNameValidationError::InvalidPart( - part.to_string(), - )); - } - - if part.len() > 24 { - return Err(StandardPackageNameValidationError::PartTooLong( - part.to_string(), - )); - } - - Ok(()) -} - -/// A wally package name -#[cfg(feature = "wally")] -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct WallyPackageName(String, String); - -/// An error that occurred while validating a wally package name part (scope or name) -#[cfg(feature = "wally")] -#[derive(Debug, Error)] -pub enum WallyPackageNameValidationError { - /// The package name part is empty - #[error("wally package name part cannot be empty")] - EmptyPart, - /// The package name part contains invalid characters (only lowercase ASCII characters, numbers, and dashes are allowed) - #[error("wally package name {0} part can only contain lowercase ASCII characters, numbers, and dashes")] - InvalidPart(String), - /// The package name part is too long (it cannot be longer than 64 characters) - #[error("wally package name {0} part cannot be longer than 64 characters")] - PartTooLong(String), -} - -/// Validates a wally package name part (scope or name) -#[cfg(feature = "wally")] -pub fn validate_wally_part(part: &str) -> Result<(), WallyPackageNameValidationError> { - if part.is_empty() { - return Err(WallyPackageNameValidationError::EmptyPart); - } - - if !part - .chars() - .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-') - { - return Err(WallyPackageNameValidationError::InvalidPart( - part.to_string(), - )); - } - - if part.len() > 64 { - return Err(WallyPackageNameValidationError::PartTooLong( - part.to_string(), - )); - } - - Ok(()) -} - -/// An error that occurred while parsing an escaped package name -#[derive(Debug, Error)] -pub enum EscapedPackageNameError { - /// This package name is missing a prefix - #[error("package name is missing prefix {0}")] - MissingPrefix(String), - - /// This is not a valid escaped package name - #[error("package name {0} is not in the format `scope{ESCAPED_SEPARATOR}name`")] - Invalid(String), - - /// The package name is invalid - #[error(transparent)] - InvalidName(#[from] E), -} - -/// An error that occurred while parsing a package name -#[derive(Debug, Error)] -pub enum FromStrPackageNameParseError { - /// This is not a valid package name - #[error("package name {0} is not in the format `scope{SEPARATOR}name`")] - Invalid(String), - - /// The package name is invalid - #[error(transparent)] - InvalidPart(#[from] E), -} - -const SEPARATOR: char = '/'; -const ESCAPED_SEPARATOR: char = '+'; - -macro_rules! name_impl { - ($Name:ident, $Error:ident, $validate:expr, $prefix:expr) => { - impl $Name { - /// Creates a new package name - pub fn new(scope: &str, name: &str) -> Result { - $validate(scope)?; - $validate(name)?; - - Ok(Self(scope.to_string(), name.to_string())) - } - - /// Parses an escaped package name - pub fn from_escaped(s: &str) -> Result> { - if !s.starts_with($prefix) { - return Err(EscapedPackageNameError::MissingPrefix($prefix.to_string())); - } - - let (scope, name) = &s[$prefix.len()..] - .split_once(ESCAPED_SEPARATOR) - .ok_or_else(|| EscapedPackageNameError::Invalid(s.to_string()))?; - Ok(Self::new(scope, name)?) - } - - /// Gets the scope of the package name - pub fn scope(&self) -> &str { - &self.0 - } - - /// Gets the name of the package name - pub fn name(&self) -> &str { - &self.1 - } - - /// Gets the escaped form (for use in file names, etc.) of the package name - pub fn escaped(&self) -> String { - format!("{}{}{ESCAPED_SEPARATOR}{}", $prefix, self.0, self.1) - } - - /// Gets the parts of the package name - pub fn parts(&self) -> (&str, &str) { - (&self.0, &self.1) - } - - /// Returns the prefix for this package name - pub fn prefix() -> &'static str { - $prefix - } - } - - impl Display for $Name { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}{}{SEPARATOR}{}", $prefix, self.0, self.1) - } - } - - impl FromStr for $Name { - type Err = FromStrPackageNameParseError<$Error>; - - fn from_str(s: &str) -> Result { - let len = if s.starts_with($prefix) { - $prefix.len() - } else { - 0 - }; - - let parts: Vec<&str> = s[len..].split(SEPARATOR).collect(); - if parts.len() != 2 { - return Err(FromStrPackageNameParseError::Invalid(s.to_string())); - } - - Ok($Name::new(parts[0], parts[1])?) - } - } - - impl Serialize for $Name { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } - } - - impl<'de> Deserialize<'de> for $Name { - fn deserialize>( - deserializer: D, - ) -> Result<$Name, D::Error> { - struct NameVisitor; - - impl<'de> Visitor<'de> for NameVisitor { - type Value = $Name; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - formatter, - "a string in the format `{}scope{SEPARATOR}name`", - $prefix - ) - } - - fn visit_str(self, v: &str) -> Result { - v.parse().map_err(E::custom) - } - } - - deserializer.deserialize_str(NameVisitor) - } - } - }; -} - -/// A package name -#[derive(Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[serde(untagged)] -pub enum PackageName { - /// A standard package name - Standard(StandardPackageName), - /// A wally package name - #[cfg(feature = "wally")] - Wally(WallyPackageName), -} - -impl PackageName { - /// Gets the scope of the package name - pub fn scope(&self) -> &str { - match self { - PackageName::Standard(name) => name.scope(), - #[cfg(feature = "wally")] - PackageName::Wally(name) => name.scope(), - } - } - - /// Gets the name of the package name - pub fn name(&self) -> &str { - match self { - PackageName::Standard(name) => name.name(), - #[cfg(feature = "wally")] - PackageName::Wally(name) => name.name(), - } - } - - /// Gets the escaped form (for use in file names, etc.) of the package name - pub fn escaped(&self) -> String { - match self { - PackageName::Standard(name) => name.escaped(), - #[cfg(feature = "wally")] - PackageName::Wally(name) => name.escaped(), - } - } - - /// Gets the parts of the package name - pub fn parts(&self) -> (&str, &str) { - match self { - PackageName::Standard(name) => name.parts(), - #[cfg(feature = "wally")] - PackageName::Wally(name) => name.parts(), - } - } - - /// Returns the prefix for this package name - pub fn prefix(&self) -> &'static str { - match self { - PackageName::Standard(_) => StandardPackageName::prefix(), - #[cfg(feature = "wally")] - PackageName::Wally(_) => WallyPackageName::prefix(), - } - } -} - -impl Display for PackageName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PackageName::Standard(name) => write!(f, "{name}"), - #[cfg(feature = "wally")] - PackageName::Wally(name) => write!(f, "{name}"), - } - } -} - -impl From for PackageName { - fn from(name: StandardPackageName) -> Self { - PackageName::Standard(name) - } -} - -#[cfg(feature = "wally")] -impl From for PackageName { - fn from(name: WallyPackageName) -> Self { - PackageName::Wally(name) - } -} - -#[cfg(feature = "wally")] -impl From for StandardPackageName { - fn from(name: WallyPackageName) -> Self { - let (scope, name) = name.parts(); - - StandardPackageName( - scope[..scope.len().min(24)].replace('-', "_"), - name[..name.len().min(24)].replace('-', "_"), - ) - } -} - -name_impl!( - StandardPackageName, - StandardPackageNameValidationError, - validate_part, - "" -); - -#[cfg(feature = "wally")] -name_impl!( - WallyPackageName, - WallyPackageNameValidationError, - validate_wally_part, - "wally#" -); - -impl<'de> Deserialize<'de> for PackageName { - fn deserialize>(deserializer: D) -> Result { - let s = String::deserialize(deserializer)?; - - cfg_if! { - if #[cfg(feature = "wally")] { - if s.starts_with(WallyPackageName::prefix()) { - return Ok(PackageName::Wally( - WallyPackageName::deserialize(s.into_deserializer())?, - )); - } - } - } - - Ok(PackageName::Standard(StandardPackageName::deserialize( - s.into_deserializer(), - )?)) - } -} - -/// An error that occurred while parsing a package name -#[derive(Debug, Error)] -pub enum FromStrPackageNameError { - /// Error parsing the package name as a standard package name - #[error("error parsing standard package name")] - Standard(#[from] FromStrPackageNameParseError), - - /// Error parsing the package name as a wally package name - #[cfg(feature = "wally")] - #[error("error parsing wally package name")] - Wally(#[from] FromStrPackageNameParseError), -} - -impl FromStr for PackageName { - type Err = FromStrPackageNameError; - - fn from_str(s: &str) -> Result { - cfg_if! { - if #[cfg(feature = "wally")] { - if s.starts_with(WallyPackageName::prefix()) { - return Ok(PackageName::Wally(WallyPackageName::from_str(s)?)); - } - } - } - - Ok(PackageName::Standard(StandardPackageName::from_str(s)?)) - } -} - -/// An error that occurred while parsing an escaped package name -#[derive(Debug, Error)] -pub enum FromEscapedStrPackageNameError { - /// Error parsing the package name as a standard package name - #[error("error parsing standard package name")] - Standard(#[from] EscapedPackageNameError), - - /// Error parsing the package name as a wally package name - #[cfg(feature = "wally")] - #[error("error parsing wally package name")] - Wally(#[from] EscapedPackageNameError), -} - -impl PackageName { - /// Like `from_str`, but for escaped package names - pub fn from_escaped_str(s: &str) -> Result { - cfg_if! { - if #[cfg(feature = "wally")] { - if s.starts_with(WallyPackageName::prefix()) { - return Ok(PackageName::Wally(WallyPackageName::from_escaped(s)?)); - } - } - } - - Ok(PackageName::Standard(StandardPackageName::from_escaped(s)?)) - } -} diff --git a/src/patches.rs b/src/patches.rs deleted file mode 100644 index b4409e9..0000000 --- a/src/patches.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::{ - fs::{read, read_dir}, - path::{Path, PathBuf}, -}; - -use git2::{ApplyLocation, Diff, DiffFormat, DiffLineType, Repository, Signature}; -use log::debug; -use semver::Version; -use thiserror::Error; - -use crate::{ - dependencies::resolution::RootLockfileNode, - package_name::{FromEscapedStrPackageNameError, PackageName}, - project::Project, - PATCHES_FOLDER, -}; - -fn make_signature<'a>() -> Result, git2::Error> { - Signature::now( - env!("CARGO_PKG_NAME"), - concat!(env!("CARGO_PKG_NAME"), "@localhost"), - ) -} - -/// Sets up a patches repository in the specified directory -pub fn setup_patches_repo>(dir: P) -> Result { - let repo = Repository::init(&dir)?; - - { - let signature = make_signature()?; - let mut index = repo.index()?; - index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; - index.write()?; - - let oid = index.write_tree()?; - let tree = repo.find_tree(oid)?; - - repo.commit(Some("HEAD"), &signature, &signature, "original", &tree, &[])?; - } - - Ok(repo) -} - -/// An error that occurred while creating patches -#[derive(Debug, Error)] -pub enum CreatePatchError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while getting a file name - #[error("failed to get file name from {0}")] - FileNameFail(PathBuf), - - /// An error that occurred while stripping a prefix - #[error("error stripping prefix {1} from path {2}")] - StripPrefixFail(#[source] std::path::StripPrefixError, PathBuf, PathBuf), -} - -/// Creates a patch for the package in the specified directory -pub fn create_patch>(dir: P) -> Result, CreatePatchError> { - let mut patches = vec![]; - let repo = Repository::open(dir.as_ref())?; - - let original = repo.head()?.peel_to_tree()?; - let diff = repo.diff_tree_to_workdir(Some(&original), None)?; - - diff.print(DiffFormat::Patch, |_delta, _hunk, line| { - match line.origin_value() { - DiffLineType::Context | DiffLineType::Addition | DiffLineType::Deletion => { - let origin = line.origin(); - let mut buffer = vec![0; origin.len_utf8()]; - origin.encode_utf8(&mut buffer); - patches.extend(buffer); - } - _ => {} - } - patches.extend(line.content()); - - true - })?; - - Ok(patches) -} - -/// An error that occurred while applying patches -#[derive(Debug, Error)] -pub enum ApplyPatchesError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while interacting with git - #[error("error interacting with git")] - Git(#[from] git2::Error), - - /// An error that occurred while getting a file name - #[error("failed to get file name from {0}")] - FileNameFail(PathBuf), - - /// An error that occurred while converting a path to a string - #[error("failed to convert path to string")] - ToStringFail, - - /// An error that occurred because a patch name was malformed - #[error("malformed patch name {0}")] - MalformedPatchName(String), - - /// An error that occurred while parsing a package name - #[error("failed to parse package name {0}")] - PackageNameParse(#[from] FromEscapedStrPackageNameError), - - /// An error that occurred while getting a file stem - #[error("failed to get file stem")] - FileStemFail, - - /// An error that occurred while reading a file - #[error("failed to read file")] - ReadFail, - - /// An error that occurred because a package was not found in the dependencies - #[error("package {0} not found in the lockfile")] - PackageNotFound(PackageName), - - /// An error that occurred because a version was not found for a package - #[error("version {0} not found for package {1}")] - VersionNotFound(Version, PackageName), - - /// An error that occurred while parsing a version - #[error("failed to parse version")] - VersionParse(#[from] semver::Error), - - /// An error that occurred while stripping a prefix - #[error("strip prefix error")] - StripPrefixFail(#[from] std::path::StripPrefixError), -} - -impl Project { - /// Applies patches for the project - pub fn apply_patches(&self, lockfile: &RootLockfileNode) -> Result<(), ApplyPatchesError> { - let patches_dir = self.path().join(PATCHES_FOLDER); - if !patches_dir.exists() { - return Ok(()); - } - - for file in read_dir(&patches_dir)? { - let file = file?; - if !file.file_type()?.is_file() { - continue; - } - - let path = file.path(); - - let file_name = path - .file_name() - .ok_or_else(|| ApplyPatchesError::FileNameFail(path.clone()))?; - let file_name = file_name.to_str().ok_or(ApplyPatchesError::ToStringFail)?; - - let (package_name, version) = file_name - .strip_suffix(".patch") - .unwrap_or(file_name) - .split_once('@') - .ok_or_else(|| ApplyPatchesError::MalformedPatchName(file_name.to_string()))?; - - let package_name = PackageName::from_escaped_str(package_name)?; - - let version = Version::parse(version)?; - - let resolved_pkg = lockfile - .children - .get(&package_name) - .ok_or_else(|| ApplyPatchesError::PackageNotFound(package_name.clone()))? - .get(&version) - .ok_or_else(|| { - ApplyPatchesError::VersionNotFound(version.clone(), package_name.clone()) - })?; - - debug!("resolved package {package_name}@{version} to {resolved_pkg}"); - - let (_, source_path) = resolved_pkg.directory(self.path()); - let diff = Diff::from_buffer(&read(&path)?)?; - - let repo = match Repository::open(&source_path) { - Ok(repo) => repo, - Err(_) => setup_patches_repo(&source_path)?, - }; - - repo.apply(&diff, ApplyLocation::Both, None)?; - - let mut index = repo.index()?; - index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; - index.write()?; - - let signature = make_signature()?; - let tree_id = index.write_tree()?; - let tree = repo.find_tree(tree_id)?; - let parent = repo.head()?.peel_to_commit()?; - repo.commit( - Some("HEAD"), - &signature, - &signature, - "applied patches", - &tree, - &[&parent], - )?; - } - - Ok(()) - } -} diff --git a/src/project.rs b/src/project.rs deleted file mode 100644 index 5c50763..0000000 --- a/src/project.rs +++ /dev/null @@ -1,326 +0,0 @@ -use log::{error, warn}; -use std::{ - collections::HashMap, - fmt::Debug, - fs::{read, File}, - path::{Path, PathBuf}, -}; - -use thiserror::Error; -use url::Url; - -use crate::{ - dependencies::{resolution::RootLockfileNode, DownloadError, UrlResolveError}, - index::Index, - linking_file::LinkingDependenciesError, - manifest::{update_sync_tool_files, Manifest, ManifestReadError}, - LOCKFILE_FILE_NAME, -}; - -/// A map of indices -pub type Indices = HashMap>; - -/// A pesde project -#[derive(Debug)] -pub struct Project { - path: PathBuf, - cache_path: PathBuf, - indices: Indices, - manifest: Manifest, - pub(crate) reqwest_client: reqwest::blocking::Client, -} - -/// Options for installing a project -pub struct InstallOptions { - locked: bool, - auto_download: bool, - lockfile: Option, -} - -impl Default for InstallOptions { - fn default() -> Self { - Self { - locked: false, - auto_download: true, - lockfile: None, - } - } -} - -impl InstallOptions { - /// Creates a new set of install options (uses the Default implementation) - pub fn new() -> Self { - Self::default() - } - - /// Makes the installation to use the lockfile, and ensure that the lockfile is up-to-date - pub fn locked(&self, locked: bool) -> Self { - Self { - locked, - lockfile: self.lockfile.clone(), - ..*self - } - } - - /// Makes the installation to automatically download the dependencies - /// Having this set to false is only useful if you want to download the dependencies yourself. An example of this is the CLI's progress bar - pub fn auto_download(&self, auto_download: bool) -> Self { - Self { - auto_download, - lockfile: self.lockfile.clone(), - ..*self - } - } - - /// Makes the installation to use the given lockfile - /// Having this set to Some is only useful if you're using auto_download = false - pub fn lockfile(&self, lockfile: RootLockfileNode) -> Self { - Self { - lockfile: Some(lockfile), - ..*self - } - } -} - -/// An error that occurred while reading the lockfile -#[derive(Debug, Error)] -pub enum ReadLockfileError { - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while deserializing the lockfile - #[error("error deserializing lockfile")] - LockfileDeser(#[source] serde_yaml::Error), -} - -/// An error that occurred while downloading a project -#[derive(Debug, Error)] -pub enum InstallProjectError { - /// An error that occurred while resolving the dependency graph - #[error("failed to resolve dependency graph")] - ResolveGraph(#[from] crate::dependencies::resolution::ResolveError), - - /// An error that occurred while downloading a package - #[error("failed to download package")] - DownloadPackage(#[from] DownloadError), - - /// An error that occurred while applying patches - #[error("error applying patches")] - ApplyPatches(#[from] crate::patches::ApplyPatchesError), - - /// An error that occurred while linking dependencies - #[error("failed to link dependencies")] - Linking(#[from] LinkingDependenciesError), - - /// An error that occurred while interacting with the file system - #[error("error interacting with the file system")] - Io(#[from] std::io::Error), - - /// An error that occurred while writing the lockfile - #[error("failed to write lockfile")] - LockfileSer(#[source] serde_yaml::Error), - - /// An error that occurred while resolving the url of a package - #[error("failed to resolve package URL")] - UrlResolve(#[from] UrlResolveError), - - /// An error that occurred while reading the lockfile - #[error("failed to read lockfile")] - ReadLockfile(#[from] ReadLockfileError), -} - -/// The name of the default index to use -pub const DEFAULT_INDEX_NAME: &str = "default"; - -pub(crate) fn get_index<'a>(indices: &'a Indices, index_name: Option<&str>) -> &'a dyn Index { - indices - .get(index_name.unwrap_or(DEFAULT_INDEX_NAME)) - .or_else(|| { - warn!( - "index `{}` not found, using default index", - index_name.unwrap_or("") - ); - indices.get(DEFAULT_INDEX_NAME) - }) - .unwrap() - .as_ref() -} - -pub(crate) fn get_index_by_url<'a>(indices: &'a Indices, url: &Url) -> &'a dyn Index { - indices - .values() - .find(|index| index.url() == url) - .map(|index| index.as_ref()) - .unwrap_or_else(|| get_index(indices, None)) -} - -#[cfg(feature = "wally")] -pub(crate) fn get_wally_index<'a>( - indices: &'a mut Indices, - url: &Url, - path: Option<&Path>, -) -> Result<&'a crate::index::WallyIndex, crate::index::RefreshError> { - if !indices.contains_key(url.as_str()) { - let default_index = indices.get(DEFAULT_INDEX_NAME).unwrap(); - let default_token = default_index.registry_auth_token().map(|t| t.to_string()); - let default_credentials_fn = default_index.credentials_fn().cloned(); - - let index = crate::index::WallyIndex::new( - url.clone(), - default_token, - path.expect("index should already exist by now"), - default_credentials_fn, - ); - - match index.refresh() { - Ok(_) => { - indices.insert(url.as_str().to_string(), Box::new(index)); - } - Err(e) => { - error!("failed to refresh wally index: {e}"); - return Err(e); - } - } - } - - Ok(indices - .get(url.as_str()) - .unwrap() - .as_any() - .downcast_ref() - .unwrap()) -} - -/// An error that occurred while creating a new project -#[derive(Debug, Error)] -pub enum NewProjectError { - /// A default index was not provided - #[error("default index not provided")] - DefaultIndexNotProvided, -} - -/// An error that occurred while creating a project from a path -#[derive(Debug, Error)] -pub enum ProjectFromPathError { - /// An error that occurred while reading the manifest - #[error("error reading manifest")] - ManifestRead(#[from] ManifestReadError), - - /// An error that occurred while creating the project - #[error("error creating project")] - NewProject(#[from] NewProjectError), -} - -impl Project { - /// Creates a new project - pub fn new, Q: AsRef>( - path: P, - cache_path: Q, - indices: Indices, - manifest: Manifest, - ) -> Result { - if !indices.contains_key(DEFAULT_INDEX_NAME) { - return Err(NewProjectError::DefaultIndexNotProvided); - } - - Ok(Self { - path: path.as_ref().to_path_buf(), - cache_path: cache_path.as_ref().to_path_buf(), - indices, - manifest, - reqwest_client: reqwest::blocking::ClientBuilder::new() - .user_agent(concat!( - env!("CARGO_PKG_NAME"), - "/", - env!("CARGO_PKG_VERSION") - )) - .build() - .unwrap(), - }) - } - - /// Creates a new project from a path (manifest will be read from the path) - pub fn from_path, Q: AsRef>( - path: P, - cache_path: Q, - indices: Indices, - ) -> Result { - let manifest = Manifest::from_path(path.as_ref())?; - - Ok(Self::new(path, cache_path, indices, manifest)?) - } - - /// Returns the indices of the project - pub fn indices(&self) -> &HashMap> { - &self.indices - } - - #[cfg(feature = "wally")] - pub(crate) fn indices_mut(&mut self) -> &mut HashMap> { - &mut self.indices - } - - /// Returns the manifest of the project - pub fn manifest(&self) -> &Manifest { - &self.manifest - } - - /// Returns the cache directory of the project - pub fn cache_dir(&self) -> &Path { - &self.cache_path - } - - /// Returns the path of the project - pub fn path(&self) -> &Path { - &self.path - } - - /// Returns the lockfile of the project - pub fn lockfile(&self) -> Result, ReadLockfileError> { - let lockfile_path = self.path.join(LOCKFILE_FILE_NAME); - - Ok(if lockfile_path.exists() { - let lockfile_contents = read(&lockfile_path)?; - let lockfile: RootLockfileNode = serde_yaml::from_slice(&lockfile_contents) - .map_err(ReadLockfileError::LockfileDeser)?; - - Some(lockfile) - } else { - None - }) - } - - /// Downloads the project's dependencies, applies patches, and links the dependencies - pub fn install(&mut self, install_options: InstallOptions) -> Result<(), InstallProjectError> { - let old_lockfile = self.lockfile()?; - - let lockfile = match install_options.lockfile { - Some(map) => map, - None => { - let manifest = self.manifest.clone(); - - manifest.dependency_graph(self, install_options.locked)? - } - }; - - if install_options.auto_download { - self.download(&lockfile)?.wait()?; - } - - self.apply_patches(&lockfile)?; - - self.link_dependencies(&lockfile)?; - - if !install_options.locked { - serde_yaml::to_writer(File::create(self.path.join(LOCKFILE_FILE_NAME))?, &lockfile) - .map_err(InstallProjectError::LockfileSer)?; - } - - if !old_lockfile.is_some_and(|old| old.name == lockfile.name) { - update_sync_tool_files(self.path(), lockfile.name.name().to_string())?; - } - - Ok(()) - } -} diff --git a/src/source/mod.rs b/src/source/mod.rs new file mode 100644 index 0000000..0e0e440 --- /dev/null +++ b/src/source/mod.rs @@ -0,0 +1,79 @@ +use std::{collections::BTreeMap, fmt::Debug, path::Path}; + +use semver::Version; +use serde::{Deserialize, Serialize}; + +use crate::Project; + +pub mod pesde; + +pub trait DependencySpecifier: Debug { + fn alias(&self) -> &str; + fn set_alias(&mut self, alias: String); +} + +pub trait PackageRef: Debug {} + +pub(crate) fn hash(struc: &S) -> String { + use std::collections::hash_map::DefaultHasher; + use std::hash::Hasher; + + let mut hasher = DefaultHasher::new(); + struc.hash(&mut hasher); + hasher.finish().to_string() +} + +pub trait PackageSource: Debug { + type Ref: PackageRef; + type Specifier: DependencySpecifier; + type RefreshError: std::error::Error; + type ResolveError: std::error::Error; + type DownloadError: std::error::Error; + + fn refresh(&self, _project: &Project) -> Result<(), Self::RefreshError> { + Ok(()) + } + + fn resolve( + &self, + specifier: &Self::Specifier, + project: &Project, + ) -> Result, Self::ResolveError>; + + fn download( + &self, + pkg_ref: &Self::Ref, + destination: &Path, + project: &Project, + ) -> Result<(), Self::DownloadError>; +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum DependencySpecifiers { + Pesde(pesde::PesdeDependencySpecifier), +} + +impl DependencySpecifiers { + pub fn alias(&self) -> &str { + match self { + DependencySpecifiers::Pesde(spec) => spec.alias(), + } + } + + pub fn set_alias(&mut self, alias: String) { + match self { + DependencySpecifiers::Pesde(spec) => spec.set_alias(alias), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum PackageRefs { + Pesde(pesde::PesdePackageRef), +} + +#[derive(Debug, Eq, PartialEq, Hash)] +pub enum PackageSources { + Pesde(pesde::PesdePackageSource), +} diff --git a/src/source/pesde.rs b/src/source/pesde.rs new file mode 100644 index 0000000..324031c --- /dev/null +++ b/src/source/pesde.rs @@ -0,0 +1,588 @@ +use std::{collections::BTreeMap, fmt::Debug, hash::Hash, path::Path}; + +use gix::remote::Direction; +use semver::{Version, VersionReq}; +use serde::{Deserialize, Serialize}; + +use crate::{ + authenticate_conn, + manifest::Target, + names::PackageName, + source::{hash, DependencySpecifier, DependencySpecifiers, PackageRef, PackageSource}, + Project, REQWEST_CLIENT, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] +pub struct PesdeDependencySpecifier { + pub name: PackageName, + pub version: VersionReq, + #[serde(default, skip_serializing_if = "String::is_empty")] + pub alias: String, +} + +impl DependencySpecifier for PesdeDependencySpecifier { + fn alias(&self) -> &str { + self.alias.as_str() + } + + fn set_alias(&mut self, alias: String) { + self.alias = alias; + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct PesdePackageRef { + name: PackageName, + version: Version, +} + +impl PackageRef for PesdePackageRef {} + +impl Ord for PesdePackageRef { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.version.cmp(&other.version) + } +} + +impl PartialOrd for PesdePackageRef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[derive(Debug, Hash, PartialEq, Eq)] +pub struct PesdePackageSource { + repo_url: gix::Url, +} + +const OWNERS_FILE: &str = "owners.yaml"; + +impl PesdePackageSource { + pub fn new(repo_url: gix::Url) -> Self { + Self { repo_url } + } + + pub fn path(&self, project: &Project) -> std::path::PathBuf { + project.data_dir.join("indices").join(hash(self)) + } + + pub(crate) fn tree<'a>( + &'a self, + repo: &'a gix::Repository, + ) -> Result> { + // this is a bare repo, so this is the actual path + let path = repo.path().to_path_buf(); + + let remote = match repo.find_default_remote(Direction::Fetch) { + Some(Ok(remote)) => remote, + Some(Err(e)) => return Err(Box::new(errors::TreeError::GetDefaultRemote(path, e))), + None => { + return Err(Box::new(errors::TreeError::NoDefaultRemote(path))); + } + }; + + let refspec = match remote.refspecs(Direction::Fetch).first() { + Some(head) => head, + None => return Err(Box::new(errors::TreeError::NoRefSpecs(path))), + }; + + let spec_ref = refspec.to_ref(); + let local_ref = match spec_ref.local() { + Some(local) => local + .to_string() + .replace('*', repo.branch_names().first().unwrap_or(&"main")), + None => return Err(Box::new(errors::TreeError::NoLocalRefSpec(path))), + }; + + let reference = match repo.find_reference(&local_ref) { + Ok(reference) => reference, + Err(e) => { + return Err(Box::new(errors::TreeError::NoReference( + local_ref.to_string(), + e, + ))) + } + }; + + let reference_name = reference.name().as_bstr().to_string(); + let id = match reference.into_fully_peeled_id() { + Ok(id) => id, + Err(e) => return Err(Box::new(errors::TreeError::CannotPeel(reference_name, e))), + }; + + let id_str = id.to_string(); + let object = match id.object() { + Ok(object) => object, + Err(e) => { + return Err(Box::new(errors::TreeError::CannotConvertToObject( + id_str, e, + ))) + } + }; + + match object.peel_to_tree() { + Ok(tree) => Ok(tree), + Err(e) => Err(Box::new(errors::TreeError::CannotPeelToTree(id_str, e))), + } + } + + pub(crate) fn read_file< + I: IntoIterator + Clone, + P: ToString + PartialEq, + >( + &self, + file_path: I, + project: &Project, + ) -> Result>, Box> { + let path = self.path(project); + + let repo = match gix::open(&path) { + Ok(repo) => repo, + Err(e) => return Err(Box::new(errors::ReadFile::Open(path, e))), + }; + + let tree = match self.tree(&repo) { + Ok(tree) => tree, + Err(e) => return Err(Box::new(errors::ReadFile::Tree(path, e))), + }; + + let file_path_str = file_path + .clone() + .into_iter() + .map(|s| s.to_string()) + .collect::>() + .join(std::path::MAIN_SEPARATOR_STR); + + let mut lookup_buf = vec![]; + let entry = match tree.lookup_entry(file_path, &mut lookup_buf) { + Ok(Some(entry)) => entry, + Ok(None) => return Ok(None), + Err(e) => return Err(Box::new(errors::ReadFile::Lookup(file_path_str, e))), + }; + + let object = match entry.object() { + Ok(object) => object, + Err(e) => return Err(Box::new(errors::ReadFile::Lookup(file_path_str, e))), + }; + + let blob = object.into_blob(); + Ok(Some(blob.data.clone())) + } + + pub fn config(&self, project: &Project) -> Result> { + let file = self + .read_file(["config.yaml"], project) + .map_err(|e| Box::new(e.into()))?; + let bytes = match file { + Some(bytes) => bytes, + None => { + return Err(Box::new(errors::ConfigError::Missing( + self.repo_url.clone(), + ))) + } + }; + + let config: IndexConfig = serde_yaml::from_slice(&bytes).map_err(|e| Box::new(e.into()))?; + + Ok(config) + } + + pub fn all_packages( + &self, + project: &Project, + ) -> Result, Box> { + let path = self.path(project); + + let repo = match gix::open(&path) { + Ok(repo) => repo, + Err(e) => return Err(Box::new(errors::AllPackagesError::Open(path, e))), + }; + + let tree = match self.tree(&repo) { + Ok(tree) => tree, + Err(e) => return Err(Box::new(errors::AllPackagesError::Tree(path, e))), + }; + + let mut packages = BTreeMap::::new(); + + for entry in tree.iter() { + let entry = match entry { + Ok(entry) => entry, + Err(e) => return Err(Box::new(errors::AllPackagesError::Decode(path, e))), + }; + + let object = match entry.object() { + Ok(object) => object, + Err(e) => return Err(Box::new(errors::AllPackagesError::Convert(path, e))), + }; + + // directories will be trees, and files will be blobs + if !matches!(object.kind, gix::object::Kind::Tree) { + continue; + } + + let package_scope = entry.filename().to_string(); + + for inner_entry in object.into_tree().iter() { + let inner_entry = match inner_entry { + Ok(entry) => entry, + Err(e) => return Err(Box::new(errors::AllPackagesError::Decode(path, e))), + }; + + let object = match inner_entry.object() { + Ok(object) => object, + Err(e) => return Err(Box::new(errors::AllPackagesError::Convert(path, e))), + }; + + if !matches!(object.kind, gix::object::Kind::Blob) { + continue; + } + + let package_name = inner_entry.filename().to_string(); + + if package_name == OWNERS_FILE { + continue; + } + + let blob = object.into_blob(); + let file: IndexFileEntry = match serde_yaml::from_slice(&blob.data) { + Ok(file) => file, + Err(e) => { + return Err(Box::new(errors::AllPackagesError::Deserialize( + package_name, + path, + e, + ))) + } + }; + + // if this panics, it's an issue with the index. + let name = format!("{package_scope}/{package_name}").parse().unwrap(); + + packages + .entry(name) + .or_default() + .insert(file.version.clone(), file); + } + } + + Ok(packages) + } +} + +impl PackageSource for PesdePackageSource { + type Ref = PesdePackageRef; + type Specifier = PesdeDependencySpecifier; + type RefreshError = errors::RefreshError; + type ResolveError = errors::ResolveError; + type DownloadError = errors::DownloadError; + + fn refresh(&self, project: &Project) -> Result<(), Self::RefreshError> { + let path = self.path(project); + if path.exists() { + let repo = match gix::open(&path) { + Ok(repo) => repo, + Err(e) => return Err(Self::RefreshError::Open(path, e)), + }; + let remote = match repo.find_default_remote(Direction::Fetch) { + Some(Ok(remote)) => remote, + Some(Err(e)) => return Err(Self::RefreshError::GetDefaultRemote(path, e)), + None => { + return Err(Self::RefreshError::NoDefaultRemote(path)); + } + }; + + let mut connection = remote + .connect(Direction::Fetch) + .map_err(|e| Self::RefreshError::Connect(self.repo_url.clone(), e))?; + + authenticate_conn(&mut connection, project.auth_config.clone()); + + connection + .prepare_fetch(gix::progress::Discard, Default::default()) + .map_err(|e| Self::RefreshError::PrepareFetch(self.repo_url.clone(), e))? + .receive(gix::progress::Discard, &false.into()) + .map_err(|e| Self::RefreshError::Read(self.repo_url.clone(), e))?; + + return Ok(()); + } + + std::fs::create_dir_all(&path)?; + let auth_config = project.auth_config.clone(); + + gix::prepare_clone_bare(self.repo_url.clone(), &path) + .map_err(|e| Self::RefreshError::Clone(self.repo_url.clone(), e))? + .configure_connection(move |c| { + authenticate_conn(c, auth_config.clone()); + Ok(()) + }) + .fetch_only(gix::progress::Discard, &false.into()) + .map_err(|e| Self::RefreshError::Fetch(self.repo_url.clone(), e))?; + + Ok(()) + } + + fn resolve( + &self, + specifier: &Self::Specifier, + project: &Project, + ) -> Result, Self::ResolveError> { + let (scope, name) = specifier.name.as_str(); + let bytes = match self.read_file([scope, name], project) { + Ok(Some(bytes)) => bytes, + Ok(None) => return Ok(BTreeMap::new()), + Err(e) => return Err(Self::ResolveError::Read(specifier.name.to_string(), e)), + }; + + let entries: Vec = serde_yaml::from_slice(&bytes) + .map_err(|e| Self::ResolveError::Parse(specifier.name.to_string(), e))?; + + Ok(entries + .into_iter() + .filter(|entry| specifier.version.matches(&entry.version)) + .map(|entry| { + ( + entry.version.clone(), + PesdePackageRef { + name: specifier.name.clone(), + version: entry.version, + }, + ) + }) + .collect()) + } + + fn download( + &self, + pkg_ref: &Self::Ref, + destination: &Path, + project: &Project, + ) -> Result<(), Self::DownloadError> { + let config = self.config(project)?; + + let (scope, name) = pkg_ref.name.as_str(); + let url = config + .download() + .replace("{PACKAGE_SCOPE}", scope) + .replace("{PACKAGE_NAME}", name) + .replace("{PACKAGE_VERSION}", &pkg_ref.version.to_string()); + + let mut response = REQWEST_CLIENT.get(url); + + if let Some(token) = &project.auth_config.pesde_token { + use secrecy::ExposeSecret; + response = + response.header("Authorization", format!("Bearer {}", token.expose_secret())); + } + + let response = response.send()?; + let bytes = response.bytes()?; + + let mut decoder = flate2::read::GzDecoder::new(bytes.as_ref()); + let mut archive = tar::Archive::new(&mut decoder); + + archive.unpack(destination)?; + + Ok(()) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +pub struct IndexConfig { + pub api: url::Url, + pub download: Option, + #[serde(default)] + pub git_allowed: bool, + #[serde(default)] + pub custom_registry_allowed: bool, + pub github_oauth_client_id: String, +} + +impl IndexConfig { + pub fn api(&self) -> &str { + self.api.as_str().trim_end_matches('/') + } + + pub fn download(&self) -> String { + self.download + .as_ref() + .unwrap_or( + &"{API_URL}/v0/packages/{PACKAGE_SCOPE}/{PACKAGE_NAME}/{PACKAGE_VERSION}" + .to_string(), + ) + .replace("{API_URL}", self.api()) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct IndexFileEntry { + pub version: Version, + pub target: Target, + #[serde(default = "chrono::Utc::now")] + pub published_at: chrono::DateTime, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub dependencies: Vec, +} + +impl Ord for IndexFileEntry { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.target + .cmp(&other.target) + .then_with(|| self.version.cmp(&other.version)) + } +} + +impl PartialOrd for IndexFileEntry { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +pub type IndexFile = BTreeMap; + +pub mod errors { + use std::path::PathBuf; + + use thiserror::Error; + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum RefreshError { + #[error("error interacting with the filesystem")] + Io(#[from] std::io::Error), + + #[error("error opening repository at {0}")] + Open(PathBuf, gix::open::Error), + + #[error("no default remote found in repository at {0}")] + NoDefaultRemote(PathBuf), + + #[error("error getting default remote from repository at {0}")] + GetDefaultRemote(PathBuf, gix::remote::find::existing::Error), + + #[error("error connecting to remote repository at {0}")] + Connect(gix::Url, gix::remote::connect::Error), + + #[error("error preparing fetch from remote repository at {0}")] + PrepareFetch(gix::Url, gix::remote::fetch::prepare::Error), + + #[error("error reading from remote repository at {0}")] + Read(gix::Url, gix::remote::fetch::Error), + + #[error("error cloning repository from {0}")] + Clone(gix::Url, gix::clone::Error), + + #[error("error fetching repository from {0}")] + Fetch(gix::Url, gix::clone::fetch::Error), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum TreeError { + #[error("error interacting with the filesystem")] + Io(#[from] std::io::Error), + + #[error("error opening repository at {0}")] + Open(PathBuf, gix::open::Error), + + #[error("no default remote found in repository at {0}")] + NoDefaultRemote(PathBuf), + + #[error("error getting default remote from repository at {0}")] + GetDefaultRemote(PathBuf, gix::remote::find::existing::Error), + + #[error("no refspecs found in repository at {0}")] + NoRefSpecs(PathBuf), + + #[error("no local refspec found in repository at {0}")] + NoLocalRefSpec(PathBuf), + + #[error("no reference found for local refspec {0}")] + NoReference(String, gix::reference::find::existing::Error), + + #[error("cannot peel reference {0}")] + CannotPeel(String, gix::reference::peel::Error), + + #[error("error converting id {0} to object")] + CannotConvertToObject(String, gix::object::find::existing::Error), + + #[error("error peeling object {0} to tree")] + CannotPeelToTree(String, gix::object::peel::to_kind::Error), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum ReadFile { + #[error("error opening repository at {0}")] + Open(PathBuf, gix::open::Error), + + #[error("error getting tree from repository at {0}")] + Tree(PathBuf, Box), + + #[error("error looking up entry {0} in tree")] + Lookup(String, gix::object::find::existing::Error), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum ResolveError { + #[error("error interacting with the filesystem")] + Io(#[from] std::io::Error), + + #[error("error reading file for {0}")] + Read(String, Box), + + #[error("error parsing file for {0}")] + Parse(String, serde_yaml::Error), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum ConfigError { + #[error("error reading config file")] + ReadFile(#[from] Box), + + #[error("error parsing config file")] + Parse(#[from] serde_yaml::Error), + + #[error("missing config file for index at {0}")] + Missing(gix::Url), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum AllPackagesError { + #[error("error opening repository at {0}")] + Open(PathBuf, gix::open::Error), + + #[error("error getting tree from repository at {0}")] + Tree(PathBuf, Box), + + #[error("error decoding entry in repository at {0}")] + Decode(PathBuf, gix::objs::decode::Error), + + #[error("error converting entry in repository at {0}")] + Convert(PathBuf, gix::object::find::existing::Error), + + #[error("error deserializing file {0} in repository at {1}")] + Deserialize(String, PathBuf, serde_yaml::Error), + } + + #[derive(Debug, Error)] + #[non_exhaustive] + pub enum DownloadError { + #[error("error reading config file")] + ReadFile(#[from] Box), + + #[error("error downloading package")] + Download(#[from] reqwest::Error), + + #[error("error unpacking package")] + Unpack(#[from] std::io::Error), + } +} diff --git a/tests/prelude.rs b/tests/prelude.rs deleted file mode 100644 index fdf52c9..0000000 --- a/tests/prelude.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::{ - any::Any, - collections::{BTreeSet, HashMap}, - sync::Arc, -}; -use url::Url; - -use pesde::{ - index::{ - ConfigError, CreatePackageVersionError, CredentialsFn, Index, IndexConfig, IndexFile, - IndexFileEntry, IndexPackageError, ScopeOwners, ScopeOwnersError, - }, - manifest::Manifest, - package_name::PackageName, -}; - -/// An in-memory implementation of the [`Index`] trait. Used for testing. -#[derive(Debug, Clone)] -pub struct InMemoryIndex { - packages: HashMap, IndexFile)>, - url: Url, -} - -impl Default for InMemoryIndex { - fn default() -> Self { - Self { - packages: HashMap::new(), - url: Url::parse("https://example.com").unwrap(), - } - } -} - -impl InMemoryIndex { - pub fn new() -> Self { - Self::default() - } - - pub fn with_scope(mut self, scope: &str, owners: BTreeSet) -> Self { - self.packages - .insert(scope.to_string(), (owners, IndexFile::default())); - self - } - - pub fn with_package(mut self, scope: &str, index_file: IndexFileEntry) -> Self { - self.packages - .entry(scope.to_string()) - .or_insert_with(|| (BTreeSet::new(), IndexFile::default())) - .1 - .insert(index_file); - self - } -} - -impl Index for InMemoryIndex { - fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError> { - Ok(self.packages.get(scope).map(|(owners, _)| owners).cloned()) - } - - fn create_scope_for( - &mut self, - scope: &str, - owners: &ScopeOwners, - ) -> Result { - self.packages - .insert(scope.to_string(), (owners.clone(), IndexFile::default())); - Ok(true) - } - - fn package(&self, name: &PackageName) -> Result, IndexPackageError> { - Ok(self - .packages - .get(name.scope()) - .map(|(_, file)| file.clone())) - } - - fn create_package_version( - &mut self, - manifest: &Manifest, - uploader: &u64, - ) -> Result, CreatePackageVersionError> { - let scope = manifest.name.scope(); - - if let Some(owners) = self.scope_owners(scope)? { - if !owners.contains(uploader) { - return Err(CreatePackageVersionError::MissingScopeOwnership); - } - } else if !self.create_scope_for(scope, &BTreeSet::from([*uploader]))? { - return Err(CreatePackageVersionError::MissingScopeOwnership); - } - - let package = self.packages.get_mut(scope).unwrap(); - - let entry: IndexFileEntry = manifest.clone().try_into()?; - package.1.insert(entry.clone()); - - Ok(Some(entry)) - } - - fn config(&self) -> Result { - Ok(IndexConfig { - download: None, - api: "http://127.0.0.1:8080".parse().unwrap(), - github_oauth_client_id: "".to_string(), - custom_registry_allowed: false, - git_allowed: false, - }) - } - - fn credentials_fn(&self) -> Option<&Arc> { - None - } - - fn url(&self) -> &Url { - &self.url - } - - fn as_any(&self) -> &dyn Any { - self - } -} diff --git a/tests/resolver.rs b/tests/resolver.rs deleted file mode 100644 index a7e748e..0000000 --- a/tests/resolver.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap}; - -use semver::Version; -use tempfile::tempdir; - -use pesde::{ - dependencies::{ - registry::{RegistryDependencySpecifier, RegistryPackageRef}, - resolution::ResolvedPackage, - DependencySpecifier, PackageRef, - }, - index::Index, - manifest::{DependencyType, Manifest, Realm}, - package_name::StandardPackageName, - project::{Project, DEFAULT_INDEX_NAME}, -}; -use prelude::*; - -mod prelude; - -#[test] -fn test_resolves_package() { - let dir = tempdir().unwrap(); - let dir_path = dir.path().to_path_buf(); - let index = InMemoryIndex::new(); - - let version_str = "0.1.0"; - let version: Version = version_str.parse().unwrap(); - let version_2_str = "0.1.1"; - let version_2: Version = version_2_str.parse().unwrap(); - - let description = "test package"; - - let pkg_name = StandardPackageName::new("test", "test").unwrap(); - - let pkg_manifest = Manifest { - name: pkg_name.clone(), - version: version.clone(), - exports: Default::default(), - path_style: Default::default(), - private: true, - realm: None, - indices: Default::default(), - #[cfg(feature = "wally")] - sourcemap_generator: None, - overrides: Default::default(), - - dependencies: Default::default(), - peer_dependencies: Default::default(), - description: Some(description.to_string()), - license: None, - authors: None, - repository: None, - }; - - let mut pkg_2_manifest = pkg_manifest.clone(); - pkg_2_manifest.version = version_2.clone(); - - let index = index - .with_scope(pkg_name.scope(), BTreeSet::from([0])) - .with_package(pkg_name.scope(), pkg_manifest.try_into().unwrap()) - .with_package(pkg_name.scope(), pkg_2_manifest.try_into().unwrap()); - - let specifier = DependencySpecifier::Registry(RegistryDependencySpecifier { - name: pkg_name.clone(), - version: format!("={version_str}").parse().unwrap(), - realm: None, - index: DEFAULT_INDEX_NAME.to_string(), - }); - let specifier_2 = DependencySpecifier::Registry(RegistryDependencySpecifier { - name: pkg_name.clone(), - version: format!(">{version_str}").parse().unwrap(), - realm: None, - index: DEFAULT_INDEX_NAME.to_string(), - }); - - let user_manifest = Manifest { - name: "test/user".parse().unwrap(), - version: version.clone(), - exports: Default::default(), - path_style: Default::default(), - private: true, - realm: None, - indices: Default::default(), - #[cfg(feature = "wally")] - sourcemap_generator: None, - overrides: Default::default(), - - dependencies: BTreeMap::from([("test".to_string(), specifier.clone())]), - peer_dependencies: BTreeMap::from([("test2".to_string(), specifier_2.clone())]), - description: Some(description.to_string()), - license: None, - authors: None, - repository: None, - }; - - let mut project = Project::new( - &dir_path, - &dir_path, - HashMap::from([( - DEFAULT_INDEX_NAME.to_string(), - Box::new(index.clone()) as Box, - )]), - user_manifest, - ) - .unwrap(); - - let manifest = project.manifest().clone(); - let graph = manifest.dependency_graph(&mut project, false).unwrap(); - assert_eq!(graph.children.len(), 1); - let versions = graph.children.get(&pkg_name.clone().into()).unwrap(); - assert_eq!(versions.len(), 2); - let resolved_pkg = versions.get(&version).unwrap(); - assert_eq!( - resolved_pkg, - &ResolvedPackage { - pkg_ref: PackageRef::Registry(RegistryPackageRef { - name: pkg_name.clone(), - version: version.clone(), - index_url: index.url().clone(), - }), - dependencies: Default::default(), - realm: Realm::Shared, - dep_type: DependencyType::Normal, - } - ); - let resolved_pkg_2 = versions.get(&version_2).unwrap(); - assert_eq!( - resolved_pkg_2, - &ResolvedPackage { - pkg_ref: PackageRef::Registry(RegistryPackageRef { - name: pkg_name.clone(), - version: version_2.clone(), - index_url: index.url().clone(), - }), - dependencies: Default::default(), - realm: Realm::Shared, - dep_type: DependencyType::Normal, - } - ); -} diff --git a/website/.eslintignore b/website/.eslintignore deleted file mode 100644 index 1a6c4db..0000000 --- a/website/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example -pnpm-lock.yaml \ No newline at end of file diff --git a/website/.eslintrc.cjs b/website/.eslintrc.cjs deleted file mode 100644 index 0b75758..0000000 --- a/website/.eslintrc.cjs +++ /dev/null @@ -1,31 +0,0 @@ -/** @type { import("eslint").Linter.Config } */ -module.exports = { - root: true, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:svelte/recommended', - 'prettier' - ], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 2020, - extraFileExtensions: ['.svelte'] - }, - env: { - browser: true, - es2017: true, - node: true - }, - overrides: [ - { - files: ['*.svelte'], - parser: 'svelte-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser' - } - } - ] -}; diff --git a/website/.gitignore b/website/.gitignore deleted file mode 100644 index 6635cf5..0000000 --- a/website/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example -vite.config.js.timestamp-* -vite.config.ts.timestamp-* diff --git a/website/.npmrc b/website/.npmrc deleted file mode 100644 index b6f27f1..0000000 --- a/website/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/website/.prettierignore b/website/.prettierignore deleted file mode 100644 index cc41cea..0000000 --- a/website/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/website/.prettierrc b/website/.prettierrc deleted file mode 100644 index 6ed0b90..0000000 --- a/website/.prettierrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": [ - "prettier-plugin-svelte" - ], - "overrides": [ - { - "files": "*.svelte", - "options": { - "parser": "svelte" - } - } - ] -} \ No newline at end of file diff --git a/website/bun.lockb b/website/bun.lockb deleted file mode 100644 index daf647a..0000000 Binary files a/website/bun.lockb and /dev/null differ diff --git a/website/package.json b/website/package.json deleted file mode 100644 index 346d953..0000000 --- a/website/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "website", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --check . && eslint .", - "format": "prettier --write ." - }, - "devDependencies": { - "@shikijs/markdown-it": "^1.1.7", - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "@types/eslint": "^8.56.0", - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^7.0.0", - "autoprefixer": "^10.4.18", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.35.1", - "postcss": "^8.4.35", - "prettier": "^3.1.1", - "prettier-plugin-svelte": "^3.1.2", - "svelte": "^4.2.7", - "svelte-check": "^3.6.0", - "tailwindcss": "^3.4.1", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^5.0.3" - }, - "type": "module", - "dependencies": { - "@fontsource-variable/hepta-slab": "^5.0.19", - "@tailwindcss/typography": "^0.5.10", - "@types/markdown-it": "^13.0.7", - "@types/pako": "^2.0.3", - "@types/tar-stream": "^3.1.3", - "events": "^3.3.0", - "isomorphic-dompurify": "^2.4.0", - "lucide-svelte": "^0.358.0", - "markdown-it": "^14.0.0", - "pako": "^2.1.0", - "shiki": "^1.1.7", - "simple-svelte-autocomplete": "^2.5.2", - "tar-stream": "^3.1.7", - "yaml": "^2.4.1" - }, - "pnpm": { - "patchedDependencies": { - "tar-stream@3.1.7": "patches/tar-stream@3.1.7.patch", - "simple-svelte-autocomplete@2.5.2": "patches/simple-svelte-autocomplete@2.5.2.patch" - } - } -} \ No newline at end of file diff --git a/website/patches/simple-svelte-autocomplete@2.5.2.patch b/website/patches/simple-svelte-autocomplete@2.5.2.patch deleted file mode 100644 index 26dd9cb..0000000 --- a/website/patches/simple-svelte-autocomplete@2.5.2.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/package.json b/package.json -index 0a796615e65323624ae9a1fdcc7c831f39dc5158..ac84dd37cf4c95223f2727d4522b8ceb74a48dff 100644 ---- a/package.json -+++ b/package.json -@@ -5,6 +5,11 @@ - "svelte": "src/SimpleAutocomplete.svelte", - "module": "dist/index.mjs", - "main": "dist/index.js", -+ "exports": { -+ ".": { -+ "svelte": "./src/SimpleAutocomplete.svelte" -+ } -+ }, - "devDependencies": { - "@babel/core": "^7.15.0", - "@babel/preset-env": "^7.16.11", diff --git a/website/patches/tar-stream@3.1.7.patch b/website/patches/tar-stream@3.1.7.patch deleted file mode 100644 index 314b56c..0000000 --- a/website/patches/tar-stream@3.1.7.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff --git a/extract.js b/extract.js -index 0ed9f82bf287aa040dd560eabbe052316223011d..16f26d49a8b0eb554b7e0a79a076027612fb4ce1 100644 ---- a/extract.js -+++ b/extract.js -@@ -1,3 +1,4 @@ -+const EventEmitter = require('events') - const { Writable, Readable, getStreamError } = require('streamx') - const FIFO = require('fast-fifo') - const b4a = require('b4a') \ No newline at end of file diff --git a/website/postcss.config.js b/website/postcss.config.js deleted file mode 100644 index 2e7af2b..0000000 --- a/website/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/website/src/app.css b/website/src/app.css deleted file mode 100644 index 74d6820..0000000 --- a/website/src/app.css +++ /dev/null @@ -1,19 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - html { - @apply font-serif; - } -} - -@layer utilities { - .overflow-text { - @apply min-w-0 whitespace-nowrap overflow-hidden text-ellipsis; - } -} - -a { - @apply text-links underline; -} diff --git a/website/src/app.d.ts b/website/src/app.d.ts deleted file mode 100644 index 743f07b..0000000 --- a/website/src/app.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// See https://kit.svelte.dev/docs/types#app -// for information about these interfaces -declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {}; diff --git a/website/src/app.html b/website/src/app.html deleted file mode 100644 index 63c9a64..0000000 --- a/website/src/app.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - %sveltekit.head% - - - -
%sveltekit.body%
- - - \ No newline at end of file diff --git a/website/src/autocomplete.d.ts b/website/src/autocomplete.d.ts deleted file mode 100644 index 5251ab2..0000000 --- a/website/src/autocomplete.d.ts +++ /dev/null @@ -1,92 +0,0 @@ -// // https://github.com/pstanoev/simple-svelte-autocomplete/issues/205#issuecomment-1960396289 -declare module 'simple-svelte-autocomplete' { - import { SvelteComponent } from 'svelte'; - import { HTMLAttributes } from 'svelte/elements'; - - export interface AutoCompleteAttributes extends HTMLAttributes { - autocompleteOffValue?: string; - className?: string; - cleanUserText?: boolean; - closeOnBlur?: boolean; - create?: boolean; - createText?: string; - delay?: number; - disabled?: boolean; - dropdownClassName?: string; - flag?: boolean; - hideArrow?: boolean; - highlightedItem?: T; - html5autocomplete?: boolean; - ignoreAccents?: boolean; - inputClassName?: string; - inputId?: string; - items?: T[]; - keywordsFieldName?: string; - labelFieldName?: string; - localFiltering?: boolean; - localSorting?: boolean; - lock?: boolean; - lowercaseKeywords?: boolean; - matchAllKeywords?: boolean; - maxItemsToShowInList?: number; - minCharactersToSearch?: number; - moreItemsText?: string; - multiple?: boolean; - name?: string; - noInputClassName?: boolean; - noInputStyles?: boolean; - noResultsText?: string; - orderableSection?: boolean; - placeholder?: string; - readonly?: boolean; - required?: boolean; - selectFirstIfEmpty?: boolean; - selectName?: string; - selectedItem?: T; - showClear?: boolean; - showLoadingIndicator?: boolean; - sortByMatchedKeywords?: boolean; - tabIndex?: number; - value?: T; - valueFieldName?: string; - } - - export interface AutoCompleteFunctions { - itemFilterFunction?: (item: T, keywords: string) => boolean; - itemSortFunction?: (item1: T, item2: T, keywords: string) => number; - keywordsCleanFunction?: (keywords: string) => string; - keywordsFunction?: (item: T) => string; - labelFunction?: (item: T) => string; - searchFunction?: (keyword: string, maxItemsToShowInList: number) => Promise | boolean; - textCleanFunction?: (string) => string; - valueFunction?: (a: T) => string; - } - - export interface AutoCompleteCallbacks { - beforeChange?: (oldSelectedItem: T, newSelectedItem: T) => boolean; - onChange?: (newSelectedItem: T) => void; - onFocus?: () => void; - onBlur?: () => void; - onCreate?: (text: string) => void; - } - - export interface AutoCompleteSlots { - item: { item: T; label: string }; - 'no-results': null; - loading: { loadingText: string }; - tag: null; - 'dropdown-header': { nbItems: number; maxItemsToShowInList: number }; - 'dropdown-footer': { nbItems: number; maxItemsToShowInList: number }; - } - - export interface AutoCompleteProps - extends AutoCompleteAttributes, - AutoCompleteCallbacks, - AutoCompleteFunctions {} - - export default class AutoComplete extends SvelteComponent< - AutoCompleteProps, - undefined, - AutoCompleteSlots - > {} -} diff --git a/website/src/lib/Codeblock.svelte b/website/src/lib/Codeblock.svelte deleted file mode 100644 index d951714..0000000 --- a/website/src/lib/Codeblock.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - - - -{#await codeToHtml(code, { theme: 'vesper', lang, transformers: [{ pre(node) { - this.addClassToHast(node, 'not-prose overflow-x-auto px-4 py-2 rounded-md'); - } }] }) then highlightedCode} - {@html highlightedCode} -{/await} diff --git a/website/src/lib/markdown.ts b/website/src/lib/markdown.ts deleted file mode 100644 index 2ebba48..0000000 --- a/website/src/lib/markdown.ts +++ /dev/null @@ -1,18 +0,0 @@ -import MarkdownIt from 'markdown-it'; -import Shiki from '@shikijs/markdown-it'; -import { writable } from 'svelte/store'; - -// nasty hack to get around the fact that @shikijs/markdown-it is async -export const md = writable(undefined); - -const it = MarkdownIt({ - html: true -}); - -Promise.all([Shiki({ theme: 'vesper' })]).then((plugins) => { - for (const plugin of plugins) { - it.use(plugin); - } - - md.set(it); -}); diff --git a/website/src/routes/+layout.svelte b/website/src/routes/+layout.svelte deleted file mode 100644 index f13117f..0000000 --- a/website/src/routes/+layout.svelte +++ /dev/null @@ -1,132 +0,0 @@ - - -
-
-
- - pesde - -
- - -
-
- -
-
-
{item?.name}
- {#if item?.description} -
- {item.description} -
- {/if} -
-
-
-
- -
- -
-
- - diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte deleted file mode 100644 index 6185fda..0000000 --- a/website/src/routes/+page.svelte +++ /dev/null @@ -1,60 +0,0 @@ - - - - pesde - - - - - -
-

- pesde - the feature-rich Roblox package manager -

-
- {tagline} -
- -
- -
-

Recently published packages

- -
diff --git a/website/src/routes/+page.ts b/website/src/routes/+page.ts deleted file mode 100644 index 48f2f80..0000000 --- a/website/src/routes/+page.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { error } from '@sveltejs/kit'; -import type { PageLoad } from './$types'; - -export const ssr = false; - -export const load: PageLoad = async ({ fetch }) => { - const latestRes = await fetch(`${import.meta.env.VITE_API_URL}/v0/search`); - - if (!latestRes.ok) { - error(latestRes.status, await latestRes.text()); - } - - const latest = (await latestRes.json()) as { - name: string; - version: string; - description?: string; - published_at: string; - }[]; - - return { - latest: latest.map((pkg) => ({ - ...pkg, - published_at: new Date(parseInt(pkg.published_at) * 1000) - })) - }; -}; diff --git a/website/src/routes/docs/+page.svelte b/website/src/routes/docs/+page.svelte deleted file mode 100644 index bfb1e00..0000000 --- a/website/src/routes/docs/+page.svelte +++ /dev/null @@ -1,258 +0,0 @@ - - - - pesde documentation - - - - - -
-

Using pesde

- -
-

Initializing a package

-

- Even if you're not making a package, but something else such as a game, you will still need to - initialize package. -

- -

This will prompt you questions, after which it will create a pesde.yaml file.

- - If you are using pesde with the `wally` feature enabled (true on releases from the GitHub - repository) then you can use to convert your wally.toml file - to pesde.yaml. This will leave you with an empty default index, so you will need to add a URL (such - as the default `https://github.com/daimond113/pesde-index`) yourself. - -
- -
-

Adding dependencies

-

- You can use the `add` command to add dependencies to your project. With the `wally` feature - enabled, you can add Wally dependencies. -

-

- If you are making a package, you can use the `--peer` argument to add a package as a peer - dependency. Peer dependencies are not installed when the package is installed, but are - required to be installed by the user of the package. This is useful for things like framework - plugins. -

-

- If you want to declare the dependency as server or development only, you can use the `--realm - server` or `--realm development` arguments respectively. The `shared` realm is the default. -

- -
- -
-

Overriding dependencies

-

- Dependency overrides allow you to use a different version of a dependency than the one - specified in the package. This is useful for sharing 1 version of a dependency. -

-

- Dependency overrides use the keys in the format of desired names separated with `>`, and - optionally other paths separated with `,`. The value is a dependency specifier. -

- - Dependency overrides do not have a command. You will need to edit the pesde.yaml file - yourself. - - -
- -
-

Removing dependencies

-

You can use the `remove` command to remove dependencies from your project.

- -
- -
-

Outdated dependencies

-

- You can list outdated dependencies with the `outdated` command. This will list all - dependencies that have a newer version available. -

- - This command only supports pesde registries, so neither Git nor Wally dependencies will be - listed. - - -
- -
-

Installing a project

-

The `install` command will install all dependencies of a project.

-

- You can use the `--locked` argument to skip resolving and read the dependencies from the - lockfile. If any changes were made from the time the lockfile was generated this will error. -

- -
- -
-

Running a bin dependency

-

- Dependencies may export a bin script. You can run this script with the `run` command. The - script will be executed with Lune. You can use the `--` argument to pass arguments to the - script. -

- - This does not support Wally dependencies. - - -
- -
-

Patching dependencies

-

- You can use the `patch` command to patch a dependency. This will output a directory in which - you can edit the dependency. After you are done, run the `patch-commit` command with the - directory as an argument to commit the changes. -

- -
- -
-

Publishing a package

-

- You can publish a package with the `publish` command. This will upload the package to the - registry. This will publish to the `default` index. -

- The official pesde registry does not support publishing packages with Wally or Git - dependencies. Dependency overrides and patches of your package as a dependency will be - ignored. - -

- Please look at the manifest format cheat sheet for more information about - the pesde.yaml file before publishing. -

-
- -
-

Searching for packages

-

- You can search for packages with the `search` command. This will list all packages that match - the query. It will search by name and description. -

- -
- -
-

Manifest format cheat sheet

-

- Here is a cheat sheet for the manifest format. This is the format of the pesde.yaml file. The - `name` and `version` fields are required. All other fields are optional. -

-

A description of each type:

-
    -
  • PACKAGE_NAME: either a STANDARD_PACKAGE_NAME or WALLY_PACKAGE_NAME
  • -
  • STANDARD_PACKAGE_NAME: refers to a package name used by pesde
  • -
  • - WALLY_PACKAGE_NAME: refers to a package name used by Wally. This will usually be prefixed - with `wally#`, although not required when this rather than `PACKAGE_NAME` is the type -
  • -
  • VERSION: a semver version specifier
  • -
  • VERSION_REQ: a semver version requirement
  • -
  • REALM: one of `shared`, `server`, or `development`
  • -
  • COMMAND: a command to run
  • -
  • - DEPENDENCY_SPECIFIER: one of REGISTRY_DEPENDENCY_SPECIFIER, GIT_DEPENDENCY_SPECIFIER, - WALLY_DEPENDENCY_SPECIFIER -
  • -
  • - REGISTRY_DEPENDENCY_SPECIFIER: an object with the following structure: - -
  • -
  • - GIT_DEPENDENCY_SPECIFIER: an object with the following structure: - -
  • -
  • - WALLY_DEPENDENCY_SPECIFIER: an object with the following structure: - -
  • -
- -

The exports field is used to specify the paths of the package's exports:

-
    -
  • - The `lib` field is a path to the file which will become the ModuleScript of the package. - This is only used for reading the types of the package. -
  • -
  • The `bin` field is a path to the file which will be ran with the `run` command.
  • -
-

- If the realm field is not specified, it will default to `shared`. If it is another value, and - the package is to be installed in a different realm, pesde will error. -

-

- The sourcemap generator command is only used for Wally and Git packages. It will be ran in a - package's directory, and must output a sourcemap file. This is used to generate a sourcemap - for the package so that types may be found and re-exported. -

-
-
diff --git a/website/src/routes/docs/Note.svelte b/website/src/routes/docs/Note.svelte deleted file mode 100644 index c0a15d9..0000000 --- a/website/src/routes/docs/Note.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -
-
Note
- -
diff --git a/website/src/routes/packages/[scope]/[name]/[version]/+page.svelte b/website/src/routes/packages/[scope]/[name]/[version]/+page.svelte deleted file mode 100644 index fb43a5b..0000000 --- a/website/src/routes/packages/[scope]/[name]/[version]/+page.svelte +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - {data.scope}/{data.name}@{data.version} - - {#if data.description} - - - {/if} - - -
-
-
-

{data.scope}/{data.name}

- {#if data.description} -
{data.description}
- {/if} -
- -
{@html markdown}
-
-
-
-
-
- -
- - -
-
-
-
Published at
-
- -
-
-
-
Installation
- -
- {#if data.license} -
-
License
-
{data.license}
-
- {/if} - {#if data.repository} -
-
Repository
- {data.repository} -
- {/if} - {#if data.authors} -
-
Authors
-
    - {#each data.authors as author} -
  • - - {author.name} - -
    - {#if author.email} - - - - {/if} - {#if author.url} - - - - {/if} -
    -
  • - {/each} -
-
- {/if} - {#if data.realm} -
-
Realm
-
{data.realm}
-
- {/if} - {#each allDependencies as [dependencies, title]} - {#if dependencies && dependencies.length > 0} -
-
{title}
- -
- {/if} - {/each} -
-
Exports
-
    -
  • -
    - Library: - {#if data.exports.lib} - - {:else} - - {/if} -
    -
  • -
  • -
    - Binary: - {#if data.exports.bin} - - {:else} - - {/if} -
    -
  • -
-
-
-
-
- - diff --git a/website/src/routes/packages/[scope]/[name]/[version]/+page.ts b/website/src/routes/packages/[scope]/[name]/[version]/+page.ts deleted file mode 100644 index 4dab722..0000000 --- a/website/src/routes/packages/[scope]/[name]/[version]/+page.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { error, redirect } from '@sveltejs/kit'; -import type { PageLoad } from './$types'; -import { extract } from 'tar-stream'; -import { inflate } from 'pako'; -import { parse } from 'yaml'; - -export const ssr = false; - -type Dependencies = ({ name: string; version: string } | { repo: string; rev: string })[]; - -const parseAuthor = (author: string) => { - const authorRegex = - /^(?.+?)(?:\s*<(?.+?)>)?(?:\s*\((?.+?)\))?(?:\s*<(?.+?)>)?(?:\s*\((?.+?)\))?$/; - const { groups } = author.match(authorRegex) ?? {}; - return { - name: groups?.name ?? author, - email: groups?.email ?? groups?.email2, - url: groups?.url ?? groups?.url2 - }; -}; - -export const load: PageLoad = async ({ params, fetch }) => { - const res = await fetch( - `${import.meta.env.VITE_API_URL}/v0/packages/${params.scope}/${params.name}/${params.version}` - ); - - if (res.status === 404) { - error(res.status, 'Package not found'); - } else if (!res.ok) { - error(res.status, await res.text()); - } - - const body = await res.arrayBuffer(); - - const extractStream = extract(); - extractStream.end(inflate(body)); - - let manifestBuffer, readmeBuffer; - - for await (const entry of extractStream) { - const read = () => { - return new Promise((resolve, reject) => { - const chunks: number[] = []; - entry.on('data', (chunk: Uint8Array) => { - chunks.push(...chunk); - }); - entry.on('end', () => { - resolve(new Uint8Array(chunks)); - }); - entry.on('error', reject); - }); - }; - - switch (entry.header.name.toLowerCase()) { - case 'pesde.yaml': { - manifestBuffer = await read(); - break; - } - case 'readme.md': - case 'readme.txt': - case 'readme': { - readmeBuffer = await read(); - break; - } - } - - entry.resume(); - } - - if (!manifestBuffer) { - error(500, 'Package is missing pesde.yaml'); - } - - const textDecoder = new TextDecoder(); - - const manifest = textDecoder.decode(manifestBuffer); - const parsed = parse(manifest, { - customTags: [ - { - tag: '!roblox', - collection: 'map' - } - ] - }) as { - version: string; - authors?: string[]; - description?: string; - license?: string; - repository?: string; - realm?: string; - dependencies?: Dependencies; - peer_dependencies?: Dependencies; - exports?: { lib?: string; bin?: string }; - }; - - if (params.version.toLowerCase() === 'latest') { - redirect(302, `/packages/${params.scope}/${params.name}/${parsed.version}`); - } - - const readme = readmeBuffer ? textDecoder.decode(readmeBuffer) : null; - - const versionsRes = await fetch( - `${import.meta.env.VITE_API_URL}/v0/packages/${params.scope}/${params.name}/versions` - ); - - if (!versionsRes.ok) { - error(versionsRes.status, await versionsRes.text()); - } - - const versions = (await versionsRes.json()) as [string, number][]; - - return { - scope: params.scope, - name: params.name, - version: parsed.version, - versions: versions.map(([version]) => version), - publishedAt: new Date( - (versions.find(([version]) => version === parsed.version)?.[1] ?? 0) * 1000 - ), - authors: parsed.authors?.map(parseAuthor), - description: parsed.description, - license: parsed.license, - readme, - repository: parsed.repository, - realm: parsed.realm, - dependencies: parsed.dependencies, - peerDependencies: parsed.peer_dependencies, - exports: { - lib: !!parsed.exports?.lib, - bin: !!parsed.exports?.bin - } - }; -}; diff --git a/website/src/routes/policies/+page.svelte b/website/src/routes/policies/+page.svelte deleted file mode 100644 index 87acede..0000000 --- a/website/src/routes/policies/+page.svelte +++ /dev/null @@ -1,71 +0,0 @@ - - Policies - - - - - -
-

Policies for content on the public pesde registry

-

- If anything is unclear, please contact us and we will be - happy to help. -

- -
-

Permitted content

-

- The pesde registry is a place for open source Roblox packages. Examples of allowed content: -

-
    -
  • Libraries
  • -
  • Frameworks
  • -
- Examples of disallowed content: -
    -
  • Malicious code
  • -
  • Illegal content
  • -
- pesde is not responsible for the content of packages. If you believe a package is malicious or contains - illegal content, please - contact us. -
- -
-

Package removal

-

- pesde does not support removing packages from the registry without a reason such as security - or complying with the law. In case you published a secret to the registry, you must regenerate - it. If you believe a package should be removed, please contact us. We will review your request and take action if necessary. -

-

- If we find that a package is breaking the permitted content policy, we will remove it from the - registry without notice. -

-

- pesde reserves the right to remove any package from the registry at any time for any reason. -

-
- -
-

Package ownership

-

- Packages are owned by scopes. The first person to publish to the scope owns the scope. If you - want to work as a team, the owner of the scope must send a pull request to the index repo adding the members' user IDs to the scope's `owners.yaml` file. -

-
- -
-

Scope squatting

-

- Scope squatting is the act of creating a scope with the intent of preventing others from using - it. Scope squatting is not allowed. If you believe a scope is being squatted, please - contact us. We will review your request and take - action if necessary. -

-
-
diff --git a/website/static/android-chrome-192x192.png b/website/static/android-chrome-192x192.png deleted file mode 100644 index 0385ed4..0000000 Binary files a/website/static/android-chrome-192x192.png and /dev/null differ diff --git a/website/static/android-chrome-512x512.png b/website/static/android-chrome-512x512.png deleted file mode 100644 index 3bdfa02..0000000 Binary files a/website/static/android-chrome-512x512.png and /dev/null differ diff --git a/website/static/apple-touch-icon.png b/website/static/apple-touch-icon.png deleted file mode 100644 index f19772f..0000000 Binary files a/website/static/apple-touch-icon.png and /dev/null differ diff --git a/website/static/browserconfig.xml b/website/static/browserconfig.xml deleted file mode 100644 index b3930d0..0000000 --- a/website/static/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - #da532c - - - diff --git a/website/static/favicon-16x16.png b/website/static/favicon-16x16.png deleted file mode 100644 index 5fa0cde..0000000 Binary files a/website/static/favicon-16x16.png and /dev/null differ diff --git a/website/static/favicon-32x32.png b/website/static/favicon-32x32.png deleted file mode 100644 index c2d8781..0000000 Binary files a/website/static/favicon-32x32.png and /dev/null differ diff --git a/website/static/favicon.ico b/website/static/favicon.ico deleted file mode 100644 index 13af675..0000000 Binary files a/website/static/favicon.ico and /dev/null differ diff --git a/website/static/logo.png b/website/static/logo.png deleted file mode 100644 index ef31b87..0000000 Binary files a/website/static/logo.png and /dev/null differ diff --git a/website/static/logo.svg b/website/static/logo.svg deleted file mode 100644 index 6eaec10..0000000 --- a/website/static/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/website/static/mstile-150x150.png b/website/static/mstile-150x150.png deleted file mode 100644 index f269d5c..0000000 Binary files a/website/static/mstile-150x150.png and /dev/null differ diff --git a/website/static/safari-pinned-tab.svg b/website/static/safari-pinned-tab.svg deleted file mode 100644 index ab4a9b2..0000000 --- a/website/static/safari-pinned-tab.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - -Created by potrace 1.14, written by Peter Selinger 2001-2017 - - - - - - diff --git a/website/static/site.webmanifest b/website/static/site.webmanifest deleted file mode 100644 index 8c1b619..0000000 --- a/website/static/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "pesde", - "short_name": "pesde", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#f8e4d5", - "background_color": "#13100F", - "display": "standalone" -} \ No newline at end of file diff --git a/website/svelte.config.js b/website/svelte.config.js deleted file mode 100644 index a5b5a02..0000000 --- a/website/svelte.config.js +++ /dev/null @@ -1,13 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - preprocess: vitePreprocess(), - - kit: { - adapter: adapter() - } -}; - -export default config; diff --git a/website/tailwind.config.js b/website/tailwind.config.js deleted file mode 100644 index 116b89e..0000000 --- a/website/tailwind.config.js +++ /dev/null @@ -1,41 +0,0 @@ -import defaultTheme from 'tailwindcss/defaultTheme'; - -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./src/**/*.{html,js,svelte,ts}'], - theme: { - extend: { - colors: { - 'standard-text': '#f8e4d5', - 'main-background': '#13100F', - 'paper-1': '#422911', - 'paper-1-alt': '#4C3C2D', - links: '#ffa360' - }, - fontFamily: { - serif: ['Hepta Slab Variable', defaultTheme.fontFamily.serif] - }, - typography: ({ theme }) => ({ - pesde: { - css: { - '--tw-prose-body': theme('colors.standard-text'), - '--tw-prose-headings': theme('colors.standard-text'), - '--tw-prose-lead': theme('colors.orange[100]'), - '--tw-prose-links': theme('colors.links'), - '--tw-prose-bold': theme('colors.orange[400]'), - '--tw-prose-counters': theme('colors.orange[300]'), - '--tw-prose-bullets': theme('colors.orange[300]'), - '--tw-prose-hr': theme('colors.orange[100]'), - '--tw-prose-quotes': theme('colors.orange[300]'), - '--tw-prose-quote-borders': theme('colors.orange[500]'), - '--tw-prose-captions': theme('colors.orange[300]'), - '--tw-prose-th-borders': theme('colors.orange[300]'), - '--tw-prose-td-borders': theme('colors.orange[300]'), - '--tw-prose-code': theme('colors.orange[300]') - } - } - }) - } - }, - plugins: [require('@tailwindcss/typography')] -}; diff --git a/website/tsconfig.json b/website/tsconfig.json deleted file mode 100644 index cf31bef..0000000 --- a/website/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" - } -} \ No newline at end of file diff --git a/website/vite.config.ts b/website/vite.config.ts deleted file mode 100644 index bbf8c7d..0000000 --- a/website/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - plugins: [sveltekit()] -});