diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 61d861c1..a9fedb99 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,10 @@ node_modules/ .svelte-kit/ theseus_gui/build/ WixTools +.direnv/ [#]*[#] # TEMPORARY: ignore my test instance and metadata -theseus_cli/launcher theseus_cli/foo + diff --git a/Cargo.lock b/Cargo.lock index e58d7bb9..3c54e629 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -34,15 +49,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" [[package]] name = "argh" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f023c76cd7975f9969f8e29f0e461decbdc7f51048ce43427107a3d192f1c9bf" +checksum = "dbb41d85d92dfab96cb95ab023c265c5e4261bb956c0fb49ca06d90c570f1958" dependencies = [ "argh_derive", "argh_shared", @@ -50,9 +65,9 @@ dependencies = [ [[package]] name = "argh_derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ad219abc0c06ca788aface2e3a1970587e3413ab70acd20e54b6ec524c1f8f" +checksum = "be69f70ef5497dd6ab331a50bd95c6ac6b8f7f17a7967838332743fbd58dc3b5" dependencies = [ "argh_shared", "heck 0.3.3", @@ -63,128 +78,15 @@ dependencies = [ [[package]] name = "argh_shared" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ashpd" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7915e26e0786f91768d23de32afafa4ee5e2ea76be21c0ecd8e14441543c1655" -dependencies = [ - "enumflags2", - "futures", - "rand 0.8.4", - "serde", - "serde_repr", - "zbus", -] - -[[package]] -name = "async-broadcast" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" -dependencies = [ - "easy-parallel", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-recursion" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-task" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" +checksum = "e6f8c380fa28aa1b36107cd97f0196474bb7241bb95a453c5c01a15ac74b2eac" [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", @@ -209,17 +111,17 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "libc", "system-deps 6.0.2", ] [[package]] name = "attohttpc" -version = "0.18.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072" +checksum = "262c3f7f5d61249d8c00e5546e2685cd15ebeeb1bc0f3cc5449350a1cb07319e" dependencies = [ "flate2", "http", @@ -234,10 +136,21 @@ dependencies = [ ] [[package]] -name = "autocfg" -version = "1.0.1" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -247,45 +160,29 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "f609ceb2c41b0d0277314a789ef0e7eb14593d5485f7c67320bed3924ebb1b33" dependencies = [ + "bincode_derive", "serde", ] +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913287a8f3e00db4c7ae1b87e9b9b8cebd6b89217eaadfc281fa5c897da35dc3" +dependencies = [ + "virtue", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[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", -] - -[[package]] -name = "blake3" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" -dependencies = [ - "arrayref", - "arrayvec 0.7.2", - "cc", - "cfg-if", - "constant_time_eq", - "digest 0.10.3", - "rayon", -] - [[package]] name = "block" version = "0.1.6" @@ -322,6 +219,27 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bstr" version = "0.2.17" @@ -333,9 +251,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byte-tools" @@ -343,6 +261,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" + [[package]] name = "byteorder" version = "1.4.3" @@ -376,17 +300,11 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - [[package]] name = "cairo-rs" -version = "0.15.6" +version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b14c80d8d1a02fa6d914b9d1afeeca9bc34257f8300d9696e1e331ae114223" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" dependencies = [ "bitflags", "cairo-sys-rs", @@ -401,16 +319,16 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ - "glib-sys 0.15.6", + "glib-sys", "libc", "system-deps 6.0.2", ] [[package]] name = "cargo_toml" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e270ef0cd868745878982f7ce470aa898d0d4bb248af67f0cf66f54617913ef" +checksum = "5809dd3e6444651fd1cdd3dbec71eca438c439a0fcc8081674a14da0afe50185" dependencies = [ "serde", "serde_derive", @@ -419,30 +337,27 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] [[package]] -name = "cfb" -version = "0.4.0" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca453e8624711b2f0f4eb47076a318feda166252a827ee25d067b43de83dcba0" -dependencies = [ - "byteorder", - "uuid", -] +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "cfg-expr" -version = "0.8.1" +name = "cfb" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +checksum = "74f89d248799e3f15f91b70917f65381062a01bb8e222700ea0e5a7ff9785f9c" dependencies = [ - "smallvec", + "byteorder", + "uuid 0.8.2", ] [[package]] @@ -456,9 +371,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295b6eb918a60a25fec0b23a5e633e74fddbaf7bb04411e65a10c366aca4b5cd" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" dependencies = [ "smallvec", ] @@ -469,12 +384,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "chrono" version = "0.4.19" @@ -485,7 +394,7 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time", + "time 0.1.44", "winapi", ] @@ -521,12 +430,19 @@ dependencies = [ ] [[package]] -name = "concurrent-queue" -version = "1.2.2" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" dependencies = [ - "cache-padded", + "bytes", + "memchr", ] [[package]] @@ -546,9 +462,9 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22bc6cd49b0ec407b680c3e380182b6ac63b73991cb7602de350352fc309b614" +checksum = "2906f2480cdc015e998deac388331a0f1c1cd88744948c749513020c83c370bc" dependencies = [ "const_format_proc_macros", ] @@ -564,12 +480,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "convert_case" version = "0.4.0" @@ -578,9 +488,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -619,64 +529,54 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.2.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3825b1e8580894917dc4468cb634a1b4e9745fddc854edad72d9c04644c0319f" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ "cfg-if", "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", "memoffset", + "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ "cfg-if", - "lazy_static", + "once_cell", ] [[package]] @@ -718,9 +618,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ "quote", "syn", @@ -734,10 +634,11 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daedalus" -version = "0.1.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71fa5e7862c4cf3c86f6250f0254875838304eb3ee6aca95df2057fb3870805" +checksum = "af1949fc56475cb37470a1abb5a113e6f70d48fbcc0c2c315a11b24040f81062" dependencies = [ + "bincode", "bytes", "chrono", "reqwest", @@ -750,72 +651,48 @@ dependencies = [ [[package]] name = "darling" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - -[[package]] -name = "darling" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" -dependencies = [ - "darling_core 0.13.1", - "darling_macro 0.13.1", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.9.3", - "syn", -] - -[[package]] -name = "darling_core" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", + "strsim", "syn", ] [[package]] name = "darling_macro" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core 0.10.2", + "darling_core", "quote", "syn", ] [[package]] -name = "darling_macro" -version = "0.13.1" +name = "dbus" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +checksum = "de0a745c25b32caa56b82a3950f5fec7893a960f4c10ca3b02060b0c38d8c2ce" dependencies = [ - "darling_core 0.13.1", - "quote", - "syn", + "libc", + "libdbus-sys", + "winapi", ] [[package]] @@ -830,23 +707,11 @@ dependencies = [ [[package]] name = "deflate" -version = "0.8.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" dependencies = [ "adler32", - "byteorder", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", ] [[package]] @@ -864,9 +729,9 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da" +checksum = "d8c8ae48e400addc32a8710c8d62d55cb84249a7d58ac4cd959daecfbaddc545" dependencies = [ "console", "tempfile", @@ -896,18 +761,6 @@ checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ "block-buffer 0.10.2", "crypto-common", - "subtle", -] - -[[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]] @@ -936,7 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -947,7 +800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -973,16 +826,17 @@ dependencies = [ ] [[package]] -name = "easy-parallel" -version = "3.2.0" +name = "embed-resource" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "ecc24ff8d764818e9ab17963b0593c535f077a513f565e75e4352d758bc4d8c0" +dependencies = [ + "cc", + "rustc_version 0.4.0", + "toml", + "vswhom", + "winreg", +] [[package]] name = "embed_plist" @@ -998,45 +852,31 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.29" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] [[package]] -name = "enumflags2" -version = "0.7.3" +name = "env_logger" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "enumflags2_derive", - "serde", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] -[[package]] -name = "enumflags2_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "event-listener" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" - [[package]] name = "eyre" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9289ed2c0440a6536e65119725cf91fc2c6b5e513bfd2e36e1134d7cca6ca12f" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" dependencies = [ "indenter", "once_cell", @@ -1069,26 +909,24 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "winapi", ] [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", - "miniz_oxide 0.4.4", + "miniz_oxide", ] [[package]] @@ -1122,6 +960,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs_extra" version = "1.2.0" @@ -1140,9 +988,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -1155,9 +1003,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -1165,15 +1013,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -1182,9 +1030,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-lite" @@ -1203,9 +1051,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", @@ -1214,21 +1062,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-channel", "futures-core", @@ -1269,9 +1117,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.15.6" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8750501d75f318c2ec0314701bc8403901303210def80bafd13f6b6059a3f45" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" dependencies = [ "bitflags", "gdk-pixbuf-sys", @@ -1282,13 +1130,13 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.15.1" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" dependencies = [ - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "gio-sys", + "glib-sys", + "gobject-sys", "libc", "system-deps 6.0.2", ] @@ -1301,9 +1149,9 @@ checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "gio-sys", + "glib-sys", + "gobject-sys", "libc", "pango-sys", "pkg-config", @@ -1317,7 +1165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" dependencies = [ "gdk-sys", - "glib-sys 0.15.6", + "glib-sys", "libc", "system-deps 6.0.2", "x11", @@ -1368,26 +1216,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "gio" -version = "0.15.6" +version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96efd8a1c00d890f6b45671916e165b5e43ccec61957d443aff6d7e44f62d348" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-io", - "gio-sys 0.15.6", + "gio-sys", "glib", "libc", "once_cell", @@ -1396,25 +1244,12 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.14.0" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", - "libc", - "system-deps 3.2.0", - "winapi", -] - -[[package]] -name = "gio-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0fa5052773f5a56b8ae47dab09d040f5d9ce1311f4f99006e16e9a08269296" -dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "libc", "system-deps 6.0.2", "winapi", @@ -1422,9 +1257,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.15.6" +version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa570813c504bdf7539a9400180c2dd4b789a819556fb86da7226d7d1b037b49" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" dependencies = [ "bitflags", "futures-channel", @@ -1432,8 +1267,8 @@ dependencies = [ "futures-executor", "futures-task", "glib-macros", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "libc", "once_cell", "smallvec", @@ -1442,13 +1277,13 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.15.6" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41bfd8d227dead0829ac142454e97531b93f576d0805d779c42bfd799c65c572" +checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" dependencies = [ "anyhow", "heck 0.4.0", - "proc-macro-crate 1.1.2", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -1457,19 +1292,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.14.0" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" -dependencies = [ - "libc", - "system-deps 3.2.0", -] - -[[package]] -name = "glib-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4366377bd56697de8aaee24e673c575d2694d72e7756324ded2b0428829a7b8" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" dependencies = [ "libc", "system-deps 6.0.2", @@ -1483,9 +1308,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", "bstr", @@ -1496,31 +1321,20 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.14.0" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" dependencies = [ - "glib-sys 0.14.0", - "libc", - "system-deps 3.2.0", -] - -[[package]] -name = "gobject-sys" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a" -dependencies = [ - "glib-sys 0.15.6", + "glib-sys", "libc", "system-deps 6.0.2", ] [[package]] name = "gtk" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d1326b36af927fe46ae2f89a8fec38c6f0d279ebc5ef07ffeeabb70300bfc" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" dependencies = [ "atk", "bitflags", @@ -1549,9 +1363,9 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "gio-sys", + "glib-sys", + "gobject-sys", "libc", "pango-sys", "system-deps 6.0.2", @@ -1564,7 +1378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" dependencies = [ "anyhow", - "proc-macro-crate 1.1.2", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -1573,9 +1387,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.7" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -1592,9 +1406,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" [[package]] name = "heck" @@ -1620,17 +1434,11 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "html5ever" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" +checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" dependencies = [ "log", "mac", @@ -1642,20 +1450,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", + "itoa 1.0.2", ] [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -1670,9 +1478,9 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" [[package]] name = "httparse" -version = "1.5.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -1681,10 +1489,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] -name = "hyper" -version = "0.14.15" +name = "humantime" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -1695,7 +1512,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", + "itoa 1.0.2", "pin-project-lite", "socket2", "tokio", @@ -1762,6 +1579,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "image" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "indenter" version = "0.3.3" @@ -1770,9 +1601,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.7.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -1780,9 +1611,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92b41dab759f9e8427c03f519c344a14655490b8db548dac1e57a75b3258391" +checksum = "20b2b533137b9cad970793453d4f921c2e91312a6d88b1085c07bc15fc51bb3b" dependencies = [ "cfb", ] @@ -1807,18 +1638,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itoa" @@ -1828,9 +1650,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "javascriptcore-rs" @@ -1849,12 +1671,40 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "libc", "system-deps 5.0.0", ] +[[package]] +name = "jni" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -1872,9 +1722,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" dependencies = [ "wasm-bindgen", ] @@ -1921,33 +1771,43 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.119" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libdbus-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" +dependencies = [ + "pkg-config", +] [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "loom" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ "cfg-if", "generator", @@ -1966,14 +1826,15 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mac-notification-sys" -version = "0.3.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" +checksum = "042f74a606175d72ca483e14e0873fe0f6c003f7af45865b17b16fdaface7203" dependencies = [ "cc", - "chrono", - "dirs 1.0.5", + "dirs-next", "objc-foundation", + "objc_id", + "time 0.3.11", ] [[package]] @@ -2022,9 +1883,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -2043,50 +1904,30 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.3.7" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", - "autocfg", ] [[package]] name = "mio" -version = "0.8.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] name = "native-tls" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" dependencies = [ "lazy_static", "libc", @@ -2102,9 +1943,9 @@ dependencies = [ [[package]] name = "ndk" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", @@ -2115,43 +1956,18 @@ dependencies = [ [[package]] name = "ndk-context" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5cc68637e21fe8f077f6a1c9e0b9ca495bb74895226b476310f613325884" - -[[package]] -name = "ndk-glue" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1454575120e3265d2442222299c711ace58ba417532ee4f0fc71b860016b93" -dependencies = [ - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-macro", - "ndk-sys", -] - -[[package]] -name = "ndk-macro" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" -dependencies = [ - "darling 0.10.2", - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", -] +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] [[package]] name = "new_debug_unreachable" @@ -2159,19 +1975,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "nix" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - [[package]] name = "nodrop" version = "0.1.14" @@ -2180,32 +1983,20 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "notify-rust" -version = "4.5.6" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367e1355a950d3e758e414f3ca1b3981a57a2aa1fa3338eb0059f5b230b6ffa4" +checksum = "a995a3d2834cefa389218e7a35156e8ce544bc95f836900da01ee0b26a07e9d4" dependencies = [ + "dbus", "mac-notification-sys", - "serde", "winrt-notification", - "zbus", - "zvariant", - "zvariant_derive", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -2213,9 +2004,20 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", "num-integer", @@ -2224,18 +2026,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -2243,25 +2045,34 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ - "proc-macro-crate 1.1.2", + "proc-macro-crate", "proc-macro2", "quote", "syn", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -2303,9 +2114,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "opaque-debug" @@ -2315,39 +2126,51 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "open" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a82915836ef43159bb6a3c64d884c42329ccd0b8afdca737cf1e3dd701709dc" +checksum = "360bcc8316bf6363aa3954c3ccc4de8add167b087e0259190a043c9514f910fe" dependencies = [ "pathdiff", - "winapi", + "windows-sys", ] [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] [[package]] -name = "openssl-probe" -version = "0.1.4" +name = "openssl-macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.71" +version = "0.9.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" dependencies = [ "autocfg", "cc", @@ -2356,21 +2179,11 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-stream" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "os_info" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023df84d545ef479cf67fd2f4459a613585c9db4852c2fad12ab70587859d340" +checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" dependencies = [ "log", "serde", @@ -2379,9 +2192,9 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3492ebca331b895fe23ed427dce2013d9b2e00c45964f12040b0db38b8ab27" +checksum = "2c92f2b54f081d635c77e7120862d48db8e91f7f21cef23ab1b4fe9971c59f55" dependencies = [ "libc", "winapi", @@ -2398,9 +2211,9 @@ dependencies = [ [[package]] name = "pango" -version = "0.15.6" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7420fc01a390ec200da7395b64d705f5d82fe03e5d0708aee422c46538be7" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" dependencies = [ "bitflags", "glib", @@ -2411,12 +2224,12 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.15.1" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "libc", "system-deps 6.0.2", ] @@ -2432,9 +2245,9 @@ dependencies = [ [[package]] name = "paris" -version = "1.5.11" +version = "1.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69d19a208bba8b94bd27d4b7a06ad153cddc6b88cb2149a668e23ce7bdb67d5" +checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810" [[package]] name = "parking" @@ -2455,12 +2268,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.1", + "parking_lot_core 0.9.3", ] [[package]] @@ -2472,24 +2285,30 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "smallvec", "windows-sys", ] +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + [[package]] name = "path-clean" version = "0.1.0" @@ -2600,7 +2419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared 0.10.0", - "rand 0.8.4", + "rand 0.8.5", ] [[package]] @@ -2651,9 +2470,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -2663,9 +2482,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "png" @@ -2681,40 +2500,21 @@ dependencies = [ [[package]] name = "png" -version = "0.16.8" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" dependencies = [ "bitflags", "crc32fast", - "deflate 0.8.6", - "miniz_oxide 0.3.7", + "deflate 1.0.0", + "miniz_oxide", ] -[[package]] -name = "polling" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" -dependencies = [ - "cfg-if", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "pollster" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" - [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "precomputed-hash" @@ -2724,9 +2524,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "pretty_assertions" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c038cb5319b9c704bf9c227c261d275bfec0ad438118a2787ce47944fb228b" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" dependencies = [ "ansi_term", "ctor", @@ -2735,19 +2535,20 @@ dependencies = [ ] [[package]] -name = "proc-macro-crate" -version = "0.1.5" +name = "pretty_env_logger" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" dependencies = [ - "toml", + "env_logger", + "log", ] [[package]] name = "proc-macro-crate" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dada8c9981fcf32929c3c0f0cd796a9284aca335565227ed88c83babb1d43dc" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", "toml", @@ -2785,18 +2586,24 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] -name = "quote" -version = "1.0.10" +name = "quick-error" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -2811,20 +2618,19 @@ dependencies = [ "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc 0.2.0", + "rand_hc", "rand_pcg", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.3", - "rand_hc 0.3.1", ] [[package]] @@ -2862,7 +2668,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.7", ] [[package]] @@ -2874,15 +2680,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core 0.6.3", -] - [[package]] name = "rand_pcg" version = "0.2.1" @@ -2894,79 +2691,38 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" dependencies = [ "cty", ] -[[package]] -name = "rayon" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom 0.2.3", - "redox_syscall 0.2.10", + "getrandom 0.2.7", + "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -2984,9 +2740,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" @@ -2999,15 +2755,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.6" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "hyper", @@ -3025,6 +2782,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-native-tls", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -3034,15 +2792,15 @@ dependencies = [ [[package]] name = "rfd" -version = "0.7.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aaf1d71ccd44689f7c2c72da1117fd8db71f72a76fe9b5c5dbb17ab903007e0" +checksum = "f121348fd3b9035ed11be1f028e8944263c30641f8c5deacf57a4320782fb402" dependencies = [ - "ashpd", "block", "dispatch", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "embed-resource", + "glib-sys", + "gobject-sys", "gtk-sys", "js-sys", "lazy_static", @@ -3050,24 +2808,11 @@ dependencies = [ "objc", "objc-foundation", "objc_id", - "pollster", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.30.0", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", + "windows 0.37.0", ] [[package]] @@ -3085,20 +2830,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.6", + "semver 1.0.10", ] [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" [[package]] name = "ryu" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "same-file" @@ -3111,12 +2856,12 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi", + "windows-sys", ] [[package]] @@ -3133,9 +2878,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.4.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -3146,9 +2891,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.4.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -3185,9 +2930,12 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -3200,18 +2948,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -3220,20 +2968,20 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.72" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ - "itoa 0.4.8", + "itoa 1.0.2", "ryu", "serde", ] [[package]] name = "serde_repr" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" dependencies = [ "proc-macro2", "quote", @@ -3242,34 +2990,33 @@ dependencies = [ [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 0.4.8", + "itoa 1.0.2", "ryu", "serde", ] [[package]] name = "serde_with" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ - "rustversion", "serde", "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling 0.13.1", + "darling", "proc-macro2", "quote", "syn", @@ -3321,9 +3068,18 @@ dependencies = [ [[package]] name = "sha1" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" @@ -3366,21 +3122,38 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "sled" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot 0.11.2", + "zstd", +] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "socket2" @@ -3393,15 +3166,29 @@ dependencies = [ ] [[package]] -name = "soup2-sys" -version = "0.1.0" +name = "soup2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f056675eda9a7417163e5f742bb119e8e1d385edd2ada8f7031a7230a3ec10a" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" dependencies = [ "bitflags", - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags", + "gio-sys", + "glib-sys", + "gobject-sys", "libc", "system-deps 5.0.0", ] @@ -3414,28 +3201,22 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "state" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" dependencies = [ "loom", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "string_cache" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" +checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" dependencies = [ - "lazy_static", "new_debug_unreachable", - "parking_lot 0.11.2", + "once_cell", + "parking_lot 0.12.1", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -3443,53 +3224,29 @@ dependencies = [ [[package]] name = "string_cache_codegen" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro2", "quote", ] -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - [[package]] name = "strum" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" dependencies = [ - "strum_macros 0.22.0", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", + "strum_macros", ] [[package]] @@ -3504,21 +3261,15 @@ dependencies = [ "syn", ] -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - [[package]] name = "syn" -version = "1.0.82" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -3531,24 +3282,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" -dependencies = [ - "anyhow", - "cfg-expr 0.8.1", - "heck 0.3.3", - "itertools", - "pkg-config", - "strum 0.21.0", - "strum_macros 0.21.1", - "thiserror", - "toml", - "version-compare 0.0.11", -] - [[package]] name = "system-deps" version = "5.0.0" @@ -3568,7 +3301,7 @@ version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" dependencies = [ - "cfg-expr 0.10.1", + "cfg-expr 0.10.3", "heck 0.4.0", "pkg-config", "toml", @@ -3598,9 +3331,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.6.2" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3b3bbc9151bce45db3cf9ccb808730c8df8786d0223f34591f6e5890503939" +checksum = "3bfe4c782f0543f667ee3b732d026b2f1c64af39cd52e726dec1ea1f2d8f6b80" dependencies = [ "bitflags", "cairo-rs", @@ -3616,24 +3349,30 @@ dependencies = [ "gdkx11-sys", "gio", "glib", - "glib-sys 0.15.6", + "glib-sys", "gtk", + "image", "instant", + "jni 0.19.0", "lazy_static", "libc", "log", "ndk", - "ndk-glue", + "ndk-context", "ndk-sys", "objc", + "once_cell", "parking_lot 0.11.2", + "paste", + "png 0.17.5", "raw-window-handle", "scopeguard", "serde", "tao-core-video-sys", "unicode-segmentation", - "windows 0.30.0", - "windows_macros", + "uuid 0.8.2", + "windows 0.37.0", + "windows-implement", "x11-dl", ] @@ -3662,16 +3401,14 @@ dependencies = [ [[package]] name = "tauri" -version = "1.0.0-rc.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0c4a4ffd1f9b02cc3e974ce902f8132fb3d08ec6cce4ca193f97d921f5bce4" +checksum = "8e1ebb60bb8f246d5351ff9b7728fdfa7a6eba72baa722ab6021d553981caba1" dependencies = [ "anyhow", "attohttpc", - "bincode", - "cfg_aliases", + "cocoa", "dirs-next", - "either", "embed_plist", "flate2", "futures", @@ -3679,19 +3416,21 @@ dependencies = [ "glib", "glob", "gtk", + "heck 0.4.0", "http", "ignore", "notify-rust", + "objc", "once_cell", "open", "os_info", "os_pipe", "percent-encoding", - "rand 0.8.4", + "rand 0.8.5", "raw-window-handle", "regex", "rfd", - "semver 1.0.6", + "semver 1.0.10", "serde", "serde_json", "serde_repr", @@ -3707,18 +3446,22 @@ dependencies = [ "thiserror", "tokio", "url", - "uuid", - "zip", + "uuid 1.1.2", + "webkit2gtk", + "webview2-com", + "windows 0.37.0", ] [[package]] name = "tauri-build" -version = "1.0.0-rc.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855e47d8cfb2219fc14d2eed2c09bfb35f9ecd71a40ca2084aeeee2d23e0b60d" +checksum = "e7b26eb3523e962b90012fedbfb744ca153d9be85e7981e00737e106d5323941" dependencies = [ "anyhow", "cargo_toml", + "heck 0.4.0", + "semver 1.0.10", "serde_json", "tauri-utils", "winres", @@ -3726,30 +3469,32 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef4656d174ba982198266da0c016573fe6c7c760e4290f05c8c384fe180007e" +checksum = "9468c5189188c820ef605dfe4937c768cb2918e9460c8093dc4ee2cbd717b262" dependencies = [ "base64", - "blake3", + "brotli", + "ico", + "png 0.17.5", "proc-macro2", "quote", "regex", + "semver 1.0.10", "serde", "serde_json", "sha2", "tauri-utils", "thiserror", - "uuid", + "uuid 1.1.2", "walkdir", - "zstd", ] [[package]] name = "tauri-macros" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0993f5a867e321d26200b2d6394cdf482bd6cc5a0e4691bcabf811544f51cd4" +checksum = "40e3ffddd7a274fc7baaa260888c971a0d95d2ef403aa16600c878b8b1c00ffe" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -3761,9 +3506,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.3.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "851cd65e2c9df4dd70a4f9e115fb2441ac89f1c80df79de0c15a448b4acd7768" +checksum = "fb7dc4db360bb40584187b6cb7834da736ce4ef2ab0914e2be98014444fa9920" dependencies = [ "gtk", "http", @@ -3773,79 +3518,90 @@ dependencies = [ "serde_json", "tauri-utils", "thiserror", - "uuid", + "uuid 1.1.2", "webview2-com", - "windows 0.30.0", + "windows 0.37.0", ] [[package]] name = "tauri-runtime-wry" -version = "0.3.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0184f95e065fb80afadf53f0a5f87a75af2da774d0524fe8cb2976fbec4a0bf2" +checksum = "c876fb3a6e7c6fe2ac466b2a6ecd83658528844b4df0914558a9bc1501b31cf3" dependencies = [ + "cocoa", "gtk", - "ico", - "infer", - "png 0.16.8", + "percent-encoding", + "rand 0.8.5", "tauri-runtime", "tauri-utils", - "uuid", + "uuid 1.1.2", + "webkit2gtk", "webview2-com", - "windows 0.30.0", + "windows 0.37.0", "wry", ] [[package]] name = "tauri-utils" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad38ad698838886bf22ecb91c4b3d1ce178fdff7901ac7bff370103a4f51e59" +checksum = "727145cb55b8897fa9f2bcea4fad31dc39394703d037c9669b40f2d1c0c2d7f3" dependencies = [ + "brotli", "ctor", "glob", "heck 0.4.0", "html5ever", "json-patch", "kuchiki", + "memchr", "phf 0.10.1", "proc-macro2", "quote", + "semver 1.0.10", "serde", "serde_json", "serde_with", - "serialize-to-javascript", "thiserror", "url", "walkdir", - "zstd", ] [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", + "fastrand", "libc", - "rand 0.8.4", - "redox_syscall 0.2.10", + "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "tendril" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" dependencies = [ "futf", "mac", "utf-8", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.1.17" @@ -3862,15 +3618,15 @@ version = "0.1.0" dependencies = [ "argh", "async-trait", + "bincode", "bytes", "chrono", "const_format", "daedalus", - "dirs 4.0.0", + "dirs", "fs_extra", "futures", "json5", - "lazy_static", "log", "once_cell", "path-clean", @@ -3880,10 +3636,11 @@ dependencies = [ "serde", "serde_json", "sha1", + "sled", "sys-info", "thiserror", "tokio", - "uuid", + "uuid 0.8.2", "zip", "zip-extensions", ] @@ -3895,15 +3652,17 @@ dependencies = [ "argh", "daedalus", "dialoguer", - "dirs 4.0.0", + "dirs", "eyre", "futures", + "log", "paris", + "pretty_env_logger", "tabled", "theseus", "tokio", "tokio-stream", - "uuid", + "uuid 0.8.2", ] [[package]] @@ -3924,18 +3683,18 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -3953,19 +3712,30 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] -name = "tinyvec" -version = "1.5.1" +name = "time" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "libc", + "num_threads", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -3978,9 +3748,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" dependencies = [ "bytes", "libc", @@ -3988,7 +3758,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -3998,9 +3768,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -4019,9 +3789,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" dependencies = [ "futures-core", "pin-project-lite", @@ -4030,38 +3800,38 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", "pin-project-lite", "tokio", + "tracing", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if", "pin-project-lite", @@ -4071,9 +3841,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ "proc-macro2", "quote", @@ -4082,18 +3852,19 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -4102,9 +3873,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.7" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" dependencies = [ "ansi_term", "lazy_static", @@ -4135,9 +3906,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" @@ -4147,24 +3918,30 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" @@ -4174,9 +3951,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -4203,10 +3980,25 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.7", "serde", ] +[[package]] +name = "uuid" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" +dependencies = [ + "getrandom 0.2.7", +] + +[[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" @@ -4231,6 +4023,32 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtue" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "757cfbfe0d17ee6f22fe97e536d463047d451b47cf9d11e2b7d1398b0ef274dd" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22025f6d8eb903ebf920ea6933b70b1e495be37e2cb4099e62c80454aaf57c39" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "waker-fn" version = "1.1.0" @@ -4266,15 +4084,21 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4282,9 +4106,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" dependencies = [ "bumpalo", "lazy_static", @@ -4297,9 +4121,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.28" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" dependencies = [ "cfg-if", "js-sys", @@ -4309,9 +4133,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4319,9 +4143,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ "proc-macro2", "quote", @@ -4332,15 +4156,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" dependencies = [ "js-sys", "wasm-bindgen", @@ -4348,67 +4172,68 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cbd39499e917de9dad36eb11c09f665eb984d432638ae7971feed98eb96df88" +checksum = "29952969fb5e10fe834a52eb29ad0814ccdfd8387159b0933edf1344a1c9cdcc" dependencies = [ "bitflags", "cairo-rs", "gdk", "gdk-sys", "gio", - "gio-sys 0.15.6", + "gio-sys", "glib", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "glib-sys", + "gobject-sys", "gtk", "gtk-sys", "javascriptcore-rs", "libc", "once_cell", + "soup2", "webkit2gtk-sys", ] [[package]] name = "webkit2gtk-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcce6f1e0fc7715d651dba29875741509f5fc12f4e2976907272a74405f2b01" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" dependencies = [ "atk-sys", "bitflags", "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", + "gio-sys", + "glib-sys", + "gobject-sys", "gtk-sys", "javascriptcore-rs-sys", "libc", "pango-sys", "pkg-config", "soup2-sys", - "system-deps 5.0.0", + "system-deps 6.0.2", ] [[package]] name = "webview2-com" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8e90ac2d9ce39cdb70017aaec641be09fbdd702b7b332b9896d053eb469524" +checksum = "a489a9420acabb3c2ed0434b6f71f6b56b9485ec32665a28dec1ee186d716e0f" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.30.0", - "windows_macros", + "windows 0.37.0", + "windows-implement", ] [[package]] name = "webview2-com-macros" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515c6c82fcee93f6edaacc72c8e233dbe4ff3ca569dce1901dfc36c404a3e99" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" dependencies = [ "proc-macro2", "quote", @@ -4417,27 +4242,18 @@ dependencies = [ [[package]] name = "webview2-com-sys" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92160310b3322397e4ff8a8285a7429d73a07a68fda44ee80879605b93e53f76" +checksum = "0258c53ee9adc0a4f8ba1c8c317588f7a58c7048a55b621d469ba75ab3709ca1" dependencies = [ "regex", "serde", "serde_json", "thiserror", - "windows 0.30.0", + "windows 0.37.0", "windows-bindgen", ] -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "wildmatch" version = "2.1.0" @@ -4489,61 +4305,74 @@ dependencies = [ [[package]] name = "windows" -version = "0.30.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" dependencies = [ - "windows_aarch64_msvc 0.30.0", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", + "windows-implement", + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", ] [[package]] name = "windows-bindgen" -version = "0.30.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944c545fcae9dd66488308f8b69aa3ba34f53714416ecfcdcbbfa4b6821e27c6" +checksum = "0bed7be31ade0af08fec9b5343e9edcc005d22b1f11859b8a59b24797f5858e8" dependencies = [ - "windows_quote", - "windows_reader", + "windows-metadata", + "windows-tokens", ] +[[package]] +name = "windows-implement" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a1062e555f7d9d66fd1130ed4f7c6ec41a47529ee0850cd0e926d95b26bb14" +dependencies = [ + "syn", + "windows-tokens", +] + +[[package]] +name = "windows-metadata" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f33f2b90a6664e369c41ab5ff262d06f048fc9685d9bf8a0e99a47750bb0463" + [[package]] name = "windows-sys" -version = "0.32.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc 0.32.0", - "windows_i686_gnu 0.32.0", - "windows_i686_msvc 0.32.0", - "windows_x86_64_gnu 0.32.0", - "windows_x86_64_msvc 0.32.0", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] [[package]] -name = "windows_aarch64_msvc" -version = "0.30.0" +name = "windows-tokens" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" +checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169" [[package]] name = "windows_aarch64_msvc" -version = "0.32.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "windows_gen" -version = "0.30.0" +name = "windows_aarch64_msvc" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30dff4d91d22520628bb94b66f2bb313cb16a09a515a32320a84a1b449bc94c0" -dependencies = [ - "windows_quote", - "windows_reader", -] +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" [[package]] name = "windows_i686_gnu" @@ -4553,15 +4382,15 @@ checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd" [[package]] name = "windows_i686_gnu" -version = "0.30.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.32.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" [[package]] name = "windows_i686_msvc" @@ -4571,39 +4400,15 @@ checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" [[package]] name = "windows_i686_msvc" -version = "0.30.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.32.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" - -[[package]] -name = "windows_macros" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ae44ab917e9005fe710d99d52d227ca0164b10a09be90649142cc3fab825d3" -dependencies = [ - "syn", - "windows_gen", - "windows_quote", - "windows_reader", -] - -[[package]] -name = "windows_quote" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f02c51a77e6248c1206aaa920802c32d50a05205e229b118d7f3afd3036667" - -[[package]] -name = "windows_reader" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44e6df0da993cda589c5ac852272fbb2a0ead67a031a017dd3eac11528a2d72" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" [[package]] name = "windows_x86_64_gnu" @@ -4613,15 +4418,15 @@ checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4" [[package]] name = "windows_x86_64_gnu" -version = "0.30.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.32.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" [[package]] name = "windows_x86_64_msvc" @@ -4631,21 +4436,21 @@ checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" [[package]] name = "windows_x86_64_msvc" -version = "0.30.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.32.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] @@ -4665,17 +4470,18 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4" dependencies = [ - "strum 0.22.0", + "strum", "windows 0.24.0", "xml-rs", ] [[package]] name = "wry" -version = "0.13.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620bfe8ed3cde9310f32a69ffc654dfd8dae4ac5a0e08d6fbf0205a996fc7f0f" +checksum = "26b1ba327c7dd4292f46bf8e6ba8e6ec2db4443b2973c9d304a359d95e0aa856" dependencies = [ + "block", "cocoa", "core-graphics", "gdk", @@ -4683,6 +4489,7 @@ dependencies = [ "glib", "gtk", "http", + "jni 0.18.0", "libc", "log", "objc", @@ -4690,15 +4497,14 @@ dependencies = [ "once_cell", "serde", "serde_json", - "sys-info", "tao", "thiserror", "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.30.0", - "windows_macros", + "windows 0.37.0", + "windows-implement", ] [[package]] @@ -4724,9 +4530,9 @@ dependencies = [ [[package]] name = "xattr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] @@ -4737,72 +4543,11 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" -[[package]] -name = "zbus" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb86f3d4592e26a48b2719742aec94f8ae6238ebde20d98183ee185d1275e9a" -dependencies = [ - "async-broadcast", - "async-channel", - "async-executor", - "async-io", - "async-lock", - "async-recursion", - "async-task", - "async-trait", - "byteorder", - "derivative", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "lazy_static", - "nix", - "once_cell", - "ordered-stream", - "rand 0.8.4", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "winapi", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36823cc10fddc3c6b19f048903262dacaf8274170e9a255784bdd8b4570a8040" -dependencies = [ - "proc-macro-crate 1.1.2", - "proc-macro2", - "quote", - "regex", - "syn", -] - -[[package]] -name = "zbus_names" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - [[package]] name = "zeroize" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" [[package]] name = "zip" @@ -4815,7 +4560,7 @@ dependencies = [ "crc32fast", "flate2", "thiserror", - "time", + "time 0.1.44", ] [[package]] @@ -4829,18 +4574,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.10.0+zstd.1.5.2" +version = "0.9.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.4+zstd.1.5.2" +version = "4.1.3+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" dependencies = [ "libc", "zstd-sys", @@ -4848,36 +4593,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.3+zstd.1.5.2" +version = "1.6.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" dependencies = [ "cc", "libc", ] - -[[package]] -name = "zvariant" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ea5dc38b2058fae6a5b79009388143dadce1e91c26a67f984a0fc0381c8033" -dependencies = [ - "byteorder", - "enumflags2", - "libc", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2cecc5a61c2a053f7f653a24cd15b3b0195d7f7ddb5042c837fb32e161fb7a" -dependencies = [ - "proc-macro-crate 1.1.2", - "proc-macro2", - "quote", - "syn", -] diff --git a/flake.lock b/flake.lock index 70fbe924..9df5a0b4 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1646893503, - "narHash": "sha256-N4Wn8FUXUC1h1DkL8X9I7VMvIv0fLLLjeJX3uFyzvRQ=", + "lastModified": 1655706580, + "narHash": "sha256-7DshIT1Ya5W9NAW7UdnYCHsGmXfOXJZCEHbbB/cCX7g=", "owner": "nix-community", "repo": "fenix", - "rev": "aad7f0a3e44ecfc9e2c5f1a45387d193c1c51aa6", + "rev": "d895003d8e03ac2fc8ffe2aa898299cbef1a7048", "type": "github" }, "original": { @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1639947939, - "narHash": "sha256-pGsM8haJadVP80GFq4xhnSpNitYNQpaXk4cnA796Cso=", + "lastModified": 1655042882, + "narHash": "sha256-9BX8Fuez5YJlN7cdPO63InoyBy7dm3VlJkkmTt6fS1A=", "owner": "nix-community", "repo": "naersk", - "rev": "2fc8ce9d3c025d59fee349c1f80be9785049d653", + "rev": "cddffb5aa211f50c4b8750adbec0bbbdfb26bb9f", "type": "github" }, "original": { @@ -43,11 +43,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646497237, - "narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=", + "lastModified": 1655624069, + "narHash": "sha256-7g1zwTdp35GMTERnSzZMWJ7PG3QdDE8VOX3WsnOkAtM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026", + "rev": "0d68d7c857fe301d49cdcd56130e0beea4ecd5aa", "type": "github" }, "original": { @@ -68,15 +68,15 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1646862342, - "narHash": "sha256-zXd3qsIcQFDFMB6p8bSpkOKjTuBTvYuM4GkPYxEfQdA=", - "owner": "rust-analyzer", + "lastModified": 1655654433, + "narHash": "sha256-auHQ0XPCiaTPSn+R3Yu4J7oZ5Zq/FS5/Da1ivvdYb/Y=", + "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "5b51cb835a356cf79cba00cf5c65d51cadeea7f1", + "rev": "427061da19723f2206fe4dcb175c9c43b9a6193d", "type": "github" }, "original": { - "owner": "rust-analyzer", + "owner": "rust-lang", "ref": "nightly", "repo": "rust-analyzer", "type": "github" @@ -84,11 +84,11 @@ }, "utils": { "locked": { - "lastModified": 1644229661, - "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 746b1363..e6399f1b 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ }; }; - outputs = inputs: + outputs = inputs@{self, ...}: inputs.utils.lib.eachDefaultSystem (system: let pkgs = import inputs.nixpkgs { inherit system; }; fenix = inputs.fenix.packages.${system}; @@ -32,13 +32,15 @@ deps = with pkgs; { global = [ - openssl pkg-config + openssl pkg-config gcc ]; gui = [ - gtk4 gdk-pixbuf atk webkitgtk + gtk4 gdk-pixbuf atk webkitgtk dbus ]; shell = [ - toolchain fenix.default.clippy git + toolchain + (with fenix; combine [toolchain default.clippy rust-analyzer]) + git jdk17 jdk8 ]; }; @@ -53,8 +55,22 @@ }; apps = { - theseus-cli = utils.mkApp { - drv = inputs.self.packages.${system}.theseus-cli; + cli = utils.mkApp { + drv = self.packages.${system}.theseus-cli; + }; + cli-test = utils.mkApp { + drv = pkgs.writeShellApplication { + name = "theseus-test-cli"; + runtimeInputs = [ + (self.packages.${system}.theseus-cli.overrideAttrs (old: old // { + release = false; + })) + ]; + text = '' + DUMMY_ID="$(printf '%0.sa' {1..32})" + theseus_cli profile run -t "" -n "Test" -i "$DUMMY_ID" "$@" + ''; + }; }; }; @@ -62,5 +78,5 @@ buildInputs = with deps; global ++ gui ++ shell; }; - }); + }) } diff --git a/theseus/Cargo.toml b/theseus/Cargo.toml index c8b5413b..619f9657 100644 --- a/theseus/Cargo.toml +++ b/theseus/Cargo.toml @@ -10,7 +10,10 @@ edition = "2018" thiserror = "1.0" async-trait = "0.1.51" -daedalus = "0.1.12" +daedalus = { version = "0.1.16", features = ["bincode"] } + +bincode = { version = "2.0.0-rc.1", features = ["serde"] } +sled = { version = "0.34.7", features = ["compression"] } reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0", features = ["derive"] } @@ -36,13 +39,9 @@ sys-info = "0.9.0" log = "0.4.14" const_format = "0.2.22" once_cell = "1.9.0" -lazy_static = "1.4" [dev-dependencies] argh = "0.1.6" pretty_assertions = "1.1.0" -[[example]] -name = "download-pack" - [features] diff --git a/theseus/examples/download-pack.rs b/theseus/examples/download-pack.rs deleted file mode 100644 index 50cba530..00000000 --- a/theseus/examples/download-pack.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::{path::PathBuf, time::Instant}; - -use argh::FromArgs; -use theseus::modpack::{fetch_modpack, pack::ModpackSide}; - -#[derive(FromArgs)] -/// Simple modpack download -struct ModpackDownloader { - /// where to download to - #[argh(positional)] - url: String, - - /// where to put the resulting pack - #[argh(option, short = 'o')] - output: Option, - - /// the sha1 hash, if you want it checked - #[argh(option, short = 'c')] - hash: Option, - - /// use verbose logging - #[argh(switch, short = 'v')] - verbose: bool, -} - -// Simple logging helper -fn debug(msg: &str, verbose: bool) { - if verbose { - println!("{}", msg); - } -} - -#[tokio::main] -pub async fn main() { - let args = argh::from_env::(); - let dest = args.output.unwrap_or(PathBuf::from("./pack-download/")); - - debug( - &format!( - "Downloading pack {} to {}", - args.url, - dest.to_str().unwrap_or("?") - ), - args.verbose, - ); - - let start = Instant::now(); - fetch_modpack(&args.url, args.hash.as_deref(), &dest, ModpackSide::Client) - .await - .unwrap(); - let end = start.elapsed(); - - println!("Download completed in {} seconds", end.as_secs_f32()); - debug("Done!", args.verbose); -} diff --git a/theseus/src/api/mod.rs b/theseus/src/api/mod.rs new file mode 100644 index 00000000..cdddd67b --- /dev/null +++ b/theseus/src/api/mod.rs @@ -0,0 +1,20 @@ +//! API for interacting with Theseus +pub mod profile; + +pub mod data { + pub use crate::{ + launcher::Credentials, + state::{ + DirectoryInfo, Hooks, JavaSettings, MemorySettings, ModLoader, + ProfileMetadata, Settings, WindowSize, + }, + }; +} + +pub mod prelude { + pub use crate::{ + data::*, + profile::{self, Profile}, + State, + }; +} diff --git a/theseus/src/api/profile.rs b/theseus/src/api/profile.rs new file mode 100644 index 00000000..6b91592c --- /dev/null +++ b/theseus/src/api/profile.rs @@ -0,0 +1,215 @@ +//! Theseus profile management interface + +pub use crate::{ + state::{JavaSettings, Profile}, + State, +}; +use daedalus as d; +use std::{future::Future, path::Path}; +use tokio::process::{Child, Command}; + +/// Add a profile to the in-memory state +pub async fn add(profile: Profile) -> crate::Result<()> { + let state = State::get().await?; + let mut profiles = state.profiles.write().await; + profiles.insert(profile)?; + + Ok(()) +} + +/// Add a path as a profile in-memory +pub async fn add_path(path: &Path) -> crate::Result<()> { + let state = State::get().await?; + let mut profiles = state.profiles.write().await; + profiles.insert_from(path).await?; + + Ok(()) +} + +/// Remove a profile +pub async fn remove(path: &Path) -> crate::Result<()> { + let state = State::get().await?; + let mut profiles = state.profiles.write().await; + profiles.remove(path)?; + + Ok(()) +} + +/// Get a profile by path, +pub async fn get(path: &Path) -> crate::Result> { + let state = State::get().await?; + let profiles = state.profiles.read().await; + + profiles.0.get(path).map_or(Ok(None), |prof| match prof { + Some(prof) => Ok(Some(prof.clone())), + None => Err(crate::Error::UnloadedProfileError( + path.display().to_string(), + )), + }) +} + +/// Check if a profile is already managed by Theseus +pub async fn is_managed(profile: &Path) -> crate::Result { + let state = State::get().await?; + let profiles = state.profiles.read().await; + Ok(profiles.0.contains_key(profile)) +} + +/// Check if a profile is loaded +pub async fn is_loaded(profile: &Path) -> crate::Result { + let state = State::get().await?; + let profiles = state.profiles.read().await; + Ok(profiles + .0 + .get(profile) + .map(Option::as_ref) + .flatten() + .is_some()) +} + +/// Edit a profile using a given asynchronous closure +pub async fn edit( + path: &Path, + action: impl Fn(&mut Profile) -> Fut, +) -> crate::Result<()> +where + Fut: Future>, +{ + let state = State::get().await.unwrap(); + let mut profiles = state.profiles.write().await; + + match profiles.0.get_mut(path) { + Some(&mut Some(ref mut profile)) => action(profile).await, + Some(&mut None) => Err(crate::Error::UnloadedProfileError( + path.display().to_string(), + )), + None => Err(crate::Error::UnmanagedProfileError( + path.display().to_string(), + )), + } +} + +/// Run Minecraft using a profile +pub async fn run( + path: &Path, + credentials: &crate::launcher::Credentials, +) -> crate::Result { + let state = State::get().await.unwrap(); + let settings = state.settings.read().await; + let profile = get(path).await?.ok_or_else(|| { + crate::Error::OtherError(format!( + "Tried to run a nonexistent or unloaded profile at path {}!", + path.display() + )) + })?; + + let version = state + .metadata + .minecraft + .versions + .iter() + .find(|it| it.id == profile.metadata.game_version.as_ref()) + .ok_or_else(|| { + crate::Error::LauncherError(format!( + "Invalid or unknown Minecraft version: {}", + profile.metadata.game_version + )) + })?; + let version_info = d::minecraft::fetch_version_info(version).await?; + + let ref pre_launch_hooks = + profile.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch; + for hook in pre_launch_hooks.iter() { + // TODO: hook parameters + let mut cmd = hook.split(' '); + let result = Command::new(cmd.next().unwrap()) + .args(&cmd.collect::>()) + .current_dir(path) + .spawn()? + .wait() + .await?; + + if !result.success() { + return Err(crate::Error::LauncherError(format!( + "Non-zero exit code for pre-launch hook: {}", + result.code().unwrap_or(-1) + ))); + } + } + + let java_install = match profile.java { + Some(JavaSettings { + install: Some(ref install), + .. + }) => install, + _ => if version_info + .java_version + .as_ref() + .filter(|it| it.major_version >= 16) + .is_some() + { + settings.java_17_path.as_ref() + } else { + settings.java_8_path.as_ref() + } + .ok_or_else(|| { + crate::Error::LauncherError(format!( + "No Java installed for version {}", + version_info.java_version.map_or(8, |it| it.major_version), + )) + })?, + }; + + if !java_install.exists() { + return Err(crate::Error::LauncherError(format!( + "Could not find Java install: {}", + java_install.display() + ))); + } + + let ref java_args = profile + .java + .as_ref() + .and_then(|it| it.extra_arguments.as_ref()) + .unwrap_or(&settings.custom_java_args); + + let wrapper = profile + .hooks + .as_ref() + .map_or(&settings.hooks.wrapper, |it| &it.wrapper); + + let ref memory = profile.memory.unwrap_or(settings.memory); + let ref resolution = profile.resolution.unwrap_or(settings.game_resolution); + + crate::launcher::launch_minecraft( + &profile.metadata.game_version, + &profile.metadata.loader_version, + &profile.path, + &java_install, + &java_args, + &wrapper, + memory, + resolution, + credentials, + ) + .await +} + +pub async fn kill(running: &mut Child) -> crate::Result<()> { + running.kill().await?; + wait_for(running).await +} + +pub async fn wait_for(running: &mut Child) -> crate::Result<()> { + let result = running.wait().await.map_err(|err| { + crate::Error::LauncherError(format!("Error running minecraft: {err}")) + })?; + + match result.success() { + false => Err(crate::Error::LauncherError(format!( + "Minecraft exited with non-zero code {}", + result.code().unwrap_or(-1) + ))), + true => Ok(()), + } +} diff --git a/theseus/src/config.rs b/theseus/src/config.rs new file mode 100644 index 00000000..eedbec89 --- /dev/null +++ b/theseus/src/config.rs @@ -0,0 +1,22 @@ +//! Configuration structs + +use once_cell::sync::Lazy; +use std::time; + +pub static BINCODE_CONFIG: Lazy = + Lazy::new(|| { + bincode::config::standard() + .with_little_endian() + .with_no_limit() + }); + +pub static REQWEST_CLIENT: Lazy = Lazy::new(|| { + reqwest::Client::builder() + .tcp_keepalive(Some(time::Duration::from_secs(10))) + .build() + .unwrap() +}); + +pub fn sled_config() -> sled::Config { + sled::Config::default().use_compression(true) +} diff --git a/theseus/src/data/meta.rs b/theseus/src/data/meta.rs deleted file mode 100644 index 3aa3f725..00000000 --- a/theseus/src/data/meta.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::{data::DataError, LAUNCHER_WORK_DIR}; -use once_cell::sync; -use serde::{Deserialize, Serialize}; -use tokio::sync::{RwLock, RwLockReadGuard}; - -const META_FILE: &str = "meta.json"; -const META_URL: &str = "https://meta.modrinth.com/gamedata"; - -static METADATA: sync::OnceCell> = sync::OnceCell::new(); - -#[derive(Clone, Serialize, Deserialize, Debug)] -pub struct Metadata { - pub minecraft: daedalus::minecraft::VersionManifest, - pub forge: daedalus::modded::Manifest, - pub fabric: daedalus::modded::Manifest, -} - -impl Metadata { - pub async fn init() -> Result<(), DataError> { - let meta_path = LAUNCHER_WORK_DIR.join(META_FILE); - - if meta_path.exists() { - let meta_data = tokio::fs::read_to_string(meta_path) - .await - .ok() - .and_then(|it| serde_json::from_str::(&it).ok()); - - if let Some(metadata) = meta_data { - METADATA.get_or_init(|| RwLock::new(metadata)); - } - } - - let future = async { - for attempt in 0..=3 { - let res = async { - let new = Self::fetch().await?; - - std::fs::write( - LAUNCHER_WORK_DIR.join(META_FILE), - &serde_json::to_string(&new)?, - )?; - - if let Some(metadata) = METADATA.get() { - *metadata.write().await = new; - } else { - METADATA.get_or_init(|| RwLock::new(new)); - } - - Ok::<(), DataError>(()) - } - .await; - - match res { - Ok(_) => { - break; - } - Err(_) if attempt <= 3 => continue, - Err(err) => { - log::warn!("Unable to fetch launcher metadata: {}", err) - } - }; - } - }; - - if METADATA.get().is_some() { - tokio::task::spawn(future); - } else { - future.await; - } - - Ok(()) - } - - pub async fn fetch() -> Result { - let (game, forge, fabric) = futures::future::join3( - daedalus::minecraft::fetch_version_manifest(Some(&format!( - "{}/minecraft/v0/manifest.json", - META_URL - ))), - daedalus::modded::fetch_manifest(&format!( - "{}/forge/v0/manifest.json", - META_URL - )), - daedalus::modded::fetch_manifest(&format!( - "{}/fabric/v0/manifest.json", - META_URL - )), - ) - .await; - - Ok(Self { - minecraft: game?, - forge: forge?, - fabric: fabric?, - }) - } - - pub async fn get<'a>() -> Result, DataError> { - let res = METADATA - .get() - .ok_or_else(|| DataError::InitializedError("metadata".to_string()))? - .read() - .await; - - Ok(res) - } -} diff --git a/theseus/src/data/mod.rs b/theseus/src/data/mod.rs deleted file mode 100644 index fb307d8a..00000000 --- a/theseus/src/data/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::io; - -pub use meta::Metadata; -pub use profiles::{Profile, Profiles}; -pub use settings::Settings; - -mod meta; -pub mod profiles; -mod settings; - -#[derive(thiserror::Error, Debug)] -pub enum DataError { - #[error("I/O error while reading data: {0}")] - IOError(#[from] io::Error), - - #[error("Daedalus error: {0}")] - DaedalusError(#[from] daedalus::Error), - - #[error("Data format error: {0}")] - FormatError(String), - - #[error("Attempted to access {0} without initializing it!")] - InitializedError(String), - - #[error("Error while serializing/deserializing data")] - SerdeError(#[from] serde_json::Error), -} diff --git a/theseus/src/data/profiles.rs b/theseus/src/data/profiles.rs deleted file mode 100644 index 5f963920..00000000 --- a/theseus/src/data/profiles.rs +++ /dev/null @@ -1,502 +0,0 @@ -use super::DataError; -use crate::launcher::ModLoader; -use daedalus::modded::LoaderVersion; -use futures::*; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; -use std::{ - collections::{HashMap, HashSet}, - path::{Path, PathBuf}, - sync::Arc, -}; -use tokio::{ - fs, - process::{Child, Command}, - sync::{Mutex, RwLock, RwLockReadGuard}, -}; - -static PROFILES: OnceCell> = OnceCell::new(); -pub const PROFILE_JSON_PATH: &str = "profile.json"; - -#[derive(Debug)] -pub struct Profiles(pub HashMap); - -// TODO: possibly add defaults to some of these values -pub const CURRENT_FORMAT_VERSION: u32 = 1; -pub const SUPPORTED_ICON_FORMATS: &[&'static str] = &[ - "bmp", "gif", "jpeg", "jpg", "jpe", "png", "svg", "svgz", "webp", "rgb", - "mp4", -]; - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Profile { - #[serde(skip)] - pub path: PathBuf, - pub metadata: Metadata, - #[serde(skip_serializing_if = "Option::is_none")] - pub java: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub memory: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub resolution: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub hooks: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Metadata { - pub name: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub icon: Option, - pub game_version: String, - #[serde(default)] - pub loader: ModLoader, - #[serde(skip_serializing_if = "Option::is_none")] - pub loader_version: Option, - pub format_version: u32, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct JavaSettings { - #[serde(skip_serializing_if = "Option::is_none")] - pub install: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub extra_arguments: Option>, -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug)] -pub struct MemorySettings { - #[serde(skip_serializing_if = "Option::is_none")] - pub minimum: Option, - pub maximum: u32, -} - -impl Default for MemorySettings { - fn default() -> Self { - Self { - minimum: None, - maximum: 2048, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug)] -pub struct WindowSize(pub u16, pub u16); - -impl Default for WindowSize { - fn default() -> Self { - Self(854, 480) - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct ProfileHooks { - #[serde(skip_serializing_if = "HashSet::is_empty", default)] - pub pre_launch: HashSet, - #[serde(skip_serializing_if = "Option::is_none")] - pub wrapper: Option, - #[serde(skip_serializing_if = "HashSet::is_empty", default)] - pub post_exit: HashSet, -} - -impl Default for ProfileHooks { - fn default() -> Self { - Self { - pre_launch: HashSet::::new(), - wrapper: None, - post_exit: HashSet::::new(), - } - } -} - -impl Profile { - pub async fn new( - name: String, - version: String, - path: PathBuf, - ) -> Result { - if name.trim().is_empty() { - return Err(DataError::FormatError(String::from( - "Empty name for instance!", - ))); - } - - Ok(Self { - path: path.canonicalize()?, - metadata: Metadata { - name, - icon: None, - game_version: version, - loader: ModLoader::Vanilla, - loader_version: None, - format_version: CURRENT_FORMAT_VERSION, - }, - java: None, - memory: None, - resolution: None, - hooks: None, - }) - } - - pub async fn run( - &self, - credentials: &crate::launcher::Credentials, - ) -> Result { - use crate::launcher::LauncherError; - let (settings, version_info) = tokio::try_join! { - super::Settings::get(), - super::Metadata::get() - .and_then(|manifest| async move { - let version = manifest - .minecraft - .versions - .iter() - .find(|it| it.id == self.metadata.game_version.as_ref()) - .ok_or_else(|| DataError::FormatError(format!( - "invalid or unknown version: {}", - self.metadata.game_version - )))?; - - Ok(daedalus::minecraft::fetch_version_info(version) - .await?) - }) - }?; - - let ref pre_launch_hooks = - self.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch; - for hook in pre_launch_hooks.iter() { - // TODO: hook parameters - let mut cmd = hook.split(' '); - let result = Command::new(cmd.next().unwrap()) - .args(&cmd.collect::>()) - .current_dir(&self.path) - .spawn()? - .wait() - .await?; - - if !result.success() { - return Err(LauncherError::ExitError( - result.code().unwrap_or(-1), - )); - } - } - - let java_install = match self.java { - Some(JavaSettings { - install: Some(ref install), - .. - }) => install, - _ => if version_info - .java_version - .as_ref() - .filter(|it| it.major_version >= 16) - .is_some() - { - settings.java_17_path.as_ref() - } else { - settings.java_8_path.as_ref() - } - .ok_or_else(|| { - LauncherError::JavaError(format!( - "No Java installed for version {}", - version_info.java_version.map_or(8, |it| it.major_version), - )) - })?, - }; - - if !java_install.exists() { - return Err(LauncherError::JavaError(format!( - "Could not find java install: {}", - java_install.display() - ))); - } - - let java_args = &self - .java - .as_ref() - .and_then(|it| it.extra_arguments.as_ref()) - .unwrap_or(&settings.custom_java_args); - - let wrapper = self - .hooks - .as_ref() - .map_or(&settings.hooks.wrapper, |it| &it.wrapper); - - let ref memory = self.memory.unwrap_or(settings.memory); - let ref resolution = - self.resolution.unwrap_or(settings.game_resolution); - - crate::launcher::launch_minecraft( - &self.metadata.game_version, - &self.metadata.loader_version, - &self.path, - &java_install, - &java_args, - &wrapper, - memory, - resolution, - credentials, - ) - .await - } - - pub async fn kill( - &self, - running: &mut Child, - ) -> Result<(), crate::launcher::LauncherError> { - running.kill().await?; - self.wait_for(running).await - } - - pub async fn wait_for( - &self, - running: &mut Child, - ) -> Result<(), crate::launcher::LauncherError> { - let result = running.wait().await.map_err(|err| { - crate::launcher::LauncherError::ProcessError { - inner: err, - process: String::from("minecraft"), - } - })?; - - match result.success() { - false => Err(crate::launcher::LauncherError::ExitError( - result.code().unwrap_or(-1), - )), - true => Ok(()), - } - } - - // TODO: deduplicate these builder methods - // They are flat like this in order to allow builder-style usage - pub fn with_name(&mut self, name: String) -> &mut Self { - self.metadata.name = name; - self - } - - pub async fn with_icon( - &mut self, - icon: &Path, - ) -> Result<&mut Self, DataError> { - let ext = icon - .extension() - .and_then(std::ffi::OsStr::to_str) - .unwrap_or(""); - - if SUPPORTED_ICON_FORMATS.contains(&ext) { - let file_name = format!("icon.{ext}"); - fs::copy(icon, &self.path.join(&file_name)).await?; - self.metadata.icon = - Some(Path::new(&format!("./{file_name}")).to_owned()); - - Ok(self) - } else { - Err(DataError::FormatError(format!( - "Unsupported image type: {ext}" - ))) - } - } - - pub fn with_game_version(&mut self, version: String) -> &mut Self { - self.metadata.game_version = version; - self - } - - pub fn with_loader( - &mut self, - loader: ModLoader, - version: Option, - ) -> &mut Self { - self.metadata.loader = loader; - self.metadata.loader_version = version; - self - } - - pub fn with_java_settings( - &mut self, - settings: Option, - ) -> &mut Self { - self.java = settings; - self - } - - pub fn with_memory( - &mut self, - settings: Option, - ) -> &mut Self { - self.memory = settings; - self - } - - pub fn with_resolution( - &mut self, - resolution: Option, - ) -> &mut Self { - self.resolution = resolution; - self - } - - pub fn with_hooks(&mut self, hooks: Option) -> &mut Self { - self.hooks = hooks; - self - } -} - -impl Profiles { - pub async fn init() -> Result<(), DataError> { - let settings = super::Settings::get().await?; - let profiles = Arc::new(Mutex::new(HashMap::new())); - - let futures = settings.profiles.clone().into_iter().map(|path| async { - let profiles = Arc::clone(&profiles); - tokio::spawn(async move { - // TODO: handle missing profiles - let mut profiles = profiles.lock().await; - let profile = Self::read_profile_from_dir(path.clone()).await?; - - profiles.insert(path, profile); - Ok(()) as Result<_, DataError> - }) - .await - .unwrap() - }); - futures::future::try_join_all(futures).await?; - - PROFILES.get_or_init(|| { - RwLock::new(Profiles( - Arc::try_unwrap(profiles).unwrap().into_inner(), - )) - }); - Ok(()) - } - - pub async fn insert(profile: Profile) -> Result<(), DataError> { - let mut profiles = PROFILES - .get() - .ok_or_else(|| { - DataError::InitializedError(String::from("profiles")) - })? - .write() - .await; - - super::Settings::get_mut() - .await? - .profiles - .insert(profile.path.clone()); - profiles.0.insert(profile.path.clone(), profile); - Ok(()) - } - - pub async fn insert_from(path: PathBuf) -> Result<(), DataError> { - Self::read_profile_from_dir(path) - .and_then(Self::insert) - .await - } - - pub async fn remove(path: &Path) -> Result, DataError> { - let path = path.canonicalize()?; - let mut profiles = PROFILES.get().unwrap().write().await; - super::Settings::get_mut().await?.profiles.remove(&path); - Ok(profiles.0.remove(&path)) - } - - pub async fn save() -> Result<(), DataError> { - let profiles = Self::get().await?; - - let futures = profiles.0.clone().into_iter().map(|(path, profile)| { - tokio::spawn(async move { - let json = tokio::task::spawn_blocking(move || { - serde_json::to_vec_pretty(&profile) - }) - .await - .unwrap()?; - - let profile_json_path = path.join(PROFILE_JSON_PATH); - fs::write(profile_json_path, json).await?; - Ok(()) as Result<(), DataError> - }) - }); - futures::future::try_join_all(futures) - .await - .unwrap() - .into_iter() - .collect::>()?; - - Ok(()) - } - - pub async fn get<'a>() -> Result, DataError> { - Ok(PROFILES - .get() - .ok_or_else(|| DataError::InitializedError("profiles".to_string()))? - .read() - .await) - } - - async fn read_profile_from_dir( - path: PathBuf, - ) -> Result { - let json = fs::read(path.join(PROFILE_JSON_PATH)).await?; - let mut profile = serde_json::from_slice::(&json)?; - profile.path = path.clone(); - Ok(profile) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use pretty_assertions::{assert_eq, assert_str_eq}; - - #[test] - fn profile_test() -> Result<(), serde_json::Error> { - let profile = Profile { - path: PathBuf::from("/tmp/nunya/beeswax"), - metadata: Metadata { - name: String::from("Example Pack"), - icon: None, - game_version: String::from("1.18.2"), - loader: ModLoader::Vanilla, - loader_version: None, - format_version: CURRENT_FORMAT_VERSION, - }, - java: JavaSettings { - install: PathBuf::from("/usr/bin/java"), - extra_arguments: Vec::new(), - }, - memory: MemorySettings { - minimum: None, - maximum: 8192, - }, - resolution: WindowSize(1920, 1080), - hooks: ProfileHooks { - pre_launch: HashSet::new(), - wrapper: None, - post_exit: HashSet::new(), - }, - }; - let json = serde_json::json!({ - "path": "/tmp/nunya/beeswax", - "metadata": { - "name": "Example Pack", - "game_version": "1.18.2", - "format_version": 1u32, - }, - "java": { - "install": "/usr/bin/java", - }, - "memory": { - "maximum": 8192u32, - }, - "resolution": (1920u16, 1080u16), - "hooks": {}, - }); - - assert_eq!(serde_json::to_value(profile.clone())?, json.clone()); - assert_str_eq!( - format!("{:?}", serde_json::from_value::(json)?), - format!("{:?}", profile), - ); - Ok(()) - } -} diff --git a/theseus/src/data/settings.rs b/theseus/src/data/settings.rs deleted file mode 100644 index 1c33697b..00000000 --- a/theseus/src/data/settings.rs +++ /dev/null @@ -1,124 +0,0 @@ -use super::profiles::*; -use std::{collections::HashSet, path::PathBuf}; - -use crate::{data::DataError, LAUNCHER_WORK_DIR}; -use once_cell::sync; -use serde::{Deserialize, Serialize}; -use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; - -const SETTINGS_FILE: &str = "settings.json"; -const ICONS_PATH: &str = "icons"; -const METADATA_DIR: &str = "meta"; -const SETTINGS_PATH_ENV: &str = "THESEUS_CONFIG_DIR"; - -static SETTINGS: sync::OnceCell> = sync::OnceCell::new(); -pub const FORMAT_VERSION: u32 = 1; - -#[derive(Clone, Serialize, Deserialize, Debug)] -#[serde(default)] -pub struct Settings { - pub memory: MemorySettings, - pub game_resolution: WindowSize, - pub custom_java_args: Vec, - pub java_8_path: Option, - pub java_17_path: Option, - pub hooks: ProfileHooks, - pub icon_path: PathBuf, - pub metadata_dir: PathBuf, - pub profiles: HashSet, - pub max_concurrent_downloads: usize, - pub version: u32, -} - -impl Default for Settings { - fn default() -> Self { - Self { - memory: MemorySettings::default(), - game_resolution: WindowSize::default(), - custom_java_args: Vec::new(), - java_8_path: None, - java_17_path: None, - hooks: ProfileHooks::default(), - icon_path: LAUNCHER_WORK_DIR.join(ICONS_PATH), - metadata_dir: LAUNCHER_WORK_DIR.join(METADATA_DIR), - profiles: HashSet::new(), - max_concurrent_downloads: 32, - version: FORMAT_VERSION, - } - } -} - -impl Settings { - pub async fn init() -> Result<(), DataError> { - let settings_path = std::env::var_os(SETTINGS_PATH_ENV) - .map_or(LAUNCHER_WORK_DIR.join(SETTINGS_FILE), PathBuf::from); - - if settings_path.exists() { - let settings_data = tokio::fs::read_to_string(settings_path) - .await - .map(|x| serde_json::from_str::(&x).ok()) - .ok() - .flatten(); - - if let Some(settings) = settings_data { - SETTINGS.get_or_init(|| RwLock::new(settings)); - } - } - - if SETTINGS.get().is_none() { - let new = Self::default(); - - tokio::fs::write( - LAUNCHER_WORK_DIR.join(SETTINGS_FILE), - &serde_json::to_string(&new)?, - ) - .await?; - - SETTINGS.get_or_init(|| RwLock::new(new)); - } - - Ok(()) - } - - pub async fn load() -> Result<(), DataError> { - let new = serde_json::from_str::(&std::fs::read_to_string( - LAUNCHER_WORK_DIR.join(SETTINGS_FILE), - )?)?; - - let mut write = SETTINGS - .get() - .ok_or_else(|| DataError::InitializedError("settings".to_string()))? - .write() - .await; - - *write = new; - - Ok(()) - } - - pub async fn save() -> Result<(), DataError> { - let settings = Self::get().await?; - - std::fs::write( - LAUNCHER_WORK_DIR.join(SETTINGS_FILE), - &serde_json::to_string_pretty(&*settings)?, - )?; - - Ok(()) - } - - pub async fn get<'a>() -> Result, DataError> { - Ok(Self::get_or_uninit::<'a>()?.read().await) - } - - pub async fn get_mut<'a>() -> Result, DataError> - { - Ok(Self::get_or_uninit::<'a>()?.write().await) - } - - fn get_or_uninit<'a>() -> Result<&'a RwLock, DataError> { - SETTINGS - .get() - .ok_or_else(|| DataError::InitializedError("settings".to_string())) - } -} diff --git a/theseus/src/error.rs b/theseus/src/error.rs new file mode 100644 index 00000000..2ba5ccc8 --- /dev/null +++ b/theseus/src/error.rs @@ -0,0 +1,55 @@ +//! Theseus error type +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Filesystem error: {0}")] + FSError(String), + + #[error("Serialization error (JSON): {0}")] + JSONError(#[from] serde_json::Error), + + #[error("Serialization error (Bincode): {0}")] + EncodeError(#[from] bincode::error::DecodeError), + + #[error("Deserialization error (Bincode): {0}")] + DecodeError(#[from] bincode::error::EncodeError), + + #[error("Database error: {0}")] + DBError(#[from] sled::Error), + + #[error("Unable to read {0} from any source")] + NoValueFor(String), + + #[error("Metadata error: {0}")] + MetadataError(#[from] daedalus::Error), + + #[error("I/O error: {0}")] + IOError(#[from] std::io::Error), + + #[error("Error launching Minecraft: {0}")] + LauncherError(String), + + #[error("Error fetching URL: {0}")] + FetchError(#[from] reqwest::Error), + + #[error("Incorrect Sha1 hash for download: {0} != {1}")] + HashError(String, String), + + #[error("Paths stored in the database need to be valid UTF-8: {0}")] + UTFError(std::path::PathBuf), + + #[error("Invalid input: {0}")] + InputError(String), + + #[error( + "Tried to access unloaded profile {0}, loading it probably failed" + )] + UnloadedProfileError(String), + + #[error("Profile {0} is not managed by Theseus!")] + UnmanagedProfileError(String), + + #[error("Error: {0}")] + OtherError(String), +} + +pub type Result = core::result::Result; diff --git a/theseus/src/launcher/args.rs b/theseus/src/launcher/args.rs index 1a444d54..4fadcb14 100644 --- a/theseus/src/launcher/args.rs +++ b/theseus/src/launcher/args.rs @@ -1,32 +1,29 @@ -use crate::data::profiles::*; -use crate::launcher::auth::provider::Credentials; -use crate::launcher::rules::parse_rules; -use crate::launcher::LauncherError; -use daedalus::get_path_from_artifact; -use daedalus::minecraft::{Argument, ArgumentValue, Library, Os, VersionType}; -use daedalus::modded::SidedDataEntry; -use std::collections::HashMap; +//! Minecraft CLI argument logic +// TODO: Rafactor this section +use super::{auth::Credentials, parse_rule}; +use crate::{ + state::{MemorySettings, WindowSize}, + util::platform::classpath_separator, +}; +use daedalus::{ + get_path_from_artifact, + minecraft::{Argument, ArgumentValue, Library, VersionType}, + modded::SidedDataEntry, +}; use std::io::{BufRead, BufReader}; -use std::path::Path; +use std::{collections::HashMap, path::Path}; use uuid::Uuid; -fn get_cp_separator() -> &'static str { - match super::download::get_os() { - Os::Osx | Os::Linux | Os::Unknown => ":", - Os::Windows => ";", - } -} - pub fn get_class_paths( libraries_path: &Path, libraries: &[Library], client_path: &Path, -) -> Result { - let mut class_paths = libraries +) -> crate::Result { + let mut cps = libraries .iter() .filter_map(|library| { if let Some(rules) = &library.rules { - if !super::rules::parse_rules(rules.as_slice()) { + if !rules.iter().all(parse_rule) { return None; } } @@ -39,10 +36,11 @@ pub fn get_class_paths( }) .collect::, _>>()?; - class_paths.push( - crate::util::absolute_path(&client_path) + cps.push( + client_path + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified class path {} does not exist", client_path.to_string_lossy() )) @@ -51,44 +49,35 @@ pub fn get_class_paths( .to_string(), ); - Ok(class_paths.join(get_cp_separator())) + Ok(cps.join(classpath_separator())) } pub fn get_class_paths_jar>( libraries_path: &Path, libraries: &[T], -) -> Result { - let class_paths = libraries +) -> crate::Result { + let cps = libraries .iter() .map(|library| get_lib_path(libraries_path, library.as_ref())) .collect::, _>>()?; - Ok(class_paths.join(get_cp_separator())) + Ok(cps.join(classpath_separator())) } -pub fn get_lib_path(libraries_path: &Path, lib: &str) -> Result { +pub fn get_lib_path(libraries_path: &Path, lib: &str) -> crate::Result { let mut path = libraries_path.to_path_buf(); path.push(get_path_from_artifact(lib.as_ref())?); - let path = crate::util::absolute_path(&path).map_err(|_| { - LauncherError::InvalidInput(format!( + let path = &path.canonicalize().map_err(|_| { + crate::Error::LauncherError(format!( "Library file at path {} does not exist", path.to_string_lossy() )) })?; - /*if !path.exists() { - if let Some(parent) = &path.parent() { - std::fs::create_dir_all(parent)?; - } - - std::fs::File::create(&path)?; - }*/ - Ok(path.to_string_lossy().to_string()) } - pub fn get_jvm_arguments( arguments: Option<&[Argument]>, natives_path: &Path, @@ -97,7 +86,7 @@ pub fn get_jvm_arguments( version_name: &str, memory: MemorySettings, custom_args: Vec, -) -> Result, LauncherError> { +) -> crate::Result> { let mut parsed_arguments = Vec::new(); if let Some(args) = arguments { @@ -113,8 +102,9 @@ pub fn get_jvm_arguments( } else { parsed_arguments.push(format!( "-Djava.library.path={}", - &crate::util::absolute_path(natives_path) - .map_err(|_| LauncherError::InvalidInput(format!( + &natives_path + .canonicalize() + .map_err(|_| crate::Error::LauncherError(format!( "Specified natives path {} does not exist", natives_path.to_string_lossy() )))? @@ -144,14 +134,15 @@ fn parse_jvm_argument( libraries_path: &Path, class_paths: &str, version_name: &str, -) -> Result { +) -> crate::Result { argument.retain(|c| !c.is_whitespace()); Ok(argument .replace( "${natives_directory}", - &crate::util::absolute_path(natives_path) + &natives_path + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified natives path {} does not exist", natives_path.to_string_lossy() )) @@ -160,9 +151,10 @@ fn parse_jvm_argument( ) .replace( "${library_directory}", - &crate::util::absolute_path(libraries_path) + &libraries_path + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified libraries path {} does not exist", libraries_path.to_string_lossy() )) @@ -170,7 +162,7 @@ fn parse_jvm_argument( .to_string_lossy() .to_string(), ) - .replace("${classpath_separator}", get_cp_separator()) + .replace("${classpath_separator}", classpath_separator()) .replace("${launcher_name}", "theseus") .replace("${launcher_version}", env!("CARGO_PKG_VERSION")) .replace("${version_name}", version_name) @@ -188,7 +180,7 @@ pub fn get_minecraft_arguments( assets_directory: &Path, version_type: &VersionType, resolution: WindowSize, -) -> Result, LauncherError> { +) -> crate::Result> { if let Some(arguments) = arguments { let mut parsed_arguments = Vec::new(); @@ -242,7 +234,7 @@ fn parse_minecraft_argument( assets_directory: &Path, version_type: &VersionType, resolution: WindowSize, -) -> Result { +) -> crate::Result { Ok(argument .replace("${auth_access_token}", access_token) .replace("${auth_session}", access_token) @@ -254,9 +246,10 @@ fn parse_minecraft_argument( .replace("${assets_index_name}", asset_index_name) .replace( "${game_directory}", - &crate::util::absolute_path(game_directory) + &game_directory + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified game directory {} does not exist", game_directory.to_string_lossy() )) @@ -266,9 +259,10 @@ fn parse_minecraft_argument( ) .replace( "${assets_root}", - &crate::util::absolute_path(assets_directory) + &assets_directory + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified assets directory {} does not exist", assets_directory.to_string_lossy() )) @@ -278,9 +272,10 @@ fn parse_minecraft_argument( ) .replace( "${game_assets}", - &crate::util::absolute_path(assets_directory) + &assets_directory + .canonicalize() .map_err(|_| { - LauncherError::InvalidInput(format!( + crate::Error::LauncherError(format!( "Specified assets directory {} does not exist", assets_directory.to_string_lossy() )) @@ -297,9 +292,9 @@ fn parse_arguments( arguments: &[Argument], parsed_arguments: &mut Vec, parse_function: F, -) -> Result<(), LauncherError> +) -> crate::Result<()> where - F: Fn(&str) -> Result, + F: Fn(&str) -> crate::Result, { for argument in arguments { match argument { @@ -311,7 +306,7 @@ where } } Argument::Ruled { rules, value } => { - if parse_rules(rules.as_slice()) { + if rules.iter().all(parse_rule) { match value { ArgumentValue::Single(arg) => { parsed_arguments.push(parse_function(arg)?); @@ -334,7 +329,7 @@ pub fn get_processor_arguments>( libraries_path: &Path, arguments: &[T], data: &HashMap, -) -> Result, LauncherError> { +) -> crate::Result> { let mut new_arguments = Vec::new(); for argument in arguments { @@ -342,7 +337,10 @@ pub fn get_processor_arguments>( if argument.as_ref().starts_with('{') { if let Some(entry) = data.get(trimmed_arg) { new_arguments.push(if entry.client.starts_with('[') { - get_lib_path(libraries_path, &entry.client[1..entry.client.len() - 1])? + get_lib_path( + libraries_path, + &entry.client[1..entry.client.len() - 1], + )? } else { entry.client.clone() }) @@ -357,15 +355,23 @@ pub fn get_processor_arguments>( Ok(new_arguments) } -pub async fn get_processor_main_class(path: String) -> Result, LauncherError> { +pub async fn get_processor_main_class( + path: String, +) -> crate::Result> { Ok(tokio::task::spawn_blocking(move || { let zipfile = std::fs::File::open(&path)?; let mut archive = zip::ZipArchive::new(zipfile).map_err(|_| { - LauncherError::ProcessorError(format!("Cannot read processor at {}", path)) + crate::Error::LauncherError(format!( + "Cannot read processor at {}", + path + )) })?; let file = archive.by_name("META-INF/MANIFEST.MF").map_err(|_| { - LauncherError::ProcessorError(format!("Cannot read processor manifest at {}", path)) + crate::Error::LauncherError(format!( + "Cannot read processor manifest at {}", + path + )) })?; let reader = BufReader::new(file); @@ -381,7 +387,8 @@ pub async fn get_processor_main_class(path: String) -> Result, La } } - Ok::, LauncherError>(None) + Ok::, crate::Error>(None) }) - .await??) + .await + .unwrap()?) } diff --git a/theseus/src/launcher/auth.rs b/theseus/src/launcher/auth.rs index 909eb5d2..d0559575 100644 --- a/theseus/src/launcher/auth.rs +++ b/theseus/src/launcher/auth.rs @@ -1,205 +1,8 @@ -pub mod api { - use serde::{Deserialize, Serialize}; - use uuid::Uuid; - - #[derive(Debug, Serialize, Deserialize)] - pub struct GameProfile { - pub id: Uuid, - pub name: String, - } - - #[derive(Debug, Deserialize)] - pub struct UserProperty { - pub name: String, - pub value: String, - } - - #[derive(Debug, Deserialize)] - pub struct User { - pub id: String, - pub username: String, - pub properties: Option>, - } - - #[derive(Debug, Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct AuthenticateResponse { - pub user: Option, - pub client_token: Uuid, - pub access_token: String, - pub available_profiles: Vec, - pub selected_profile: Option, - } - - pub async fn login( - username: &str, - password: &str, - request_user: bool, - ) -> Result { - let client = reqwest::Client::new(); - - client - .post("https://authserver.mojang.com/authenticate") - .header(reqwest::header::CONTENT_TYPE, "application/json") - .body( - serde_json::json!( - { - "agent": { - "name": "Minecraft", - "version": 1 - }, - "username": username, - "password": password, - "clientToken": Uuid::new_v4(), - "requestUser": request_user - } - ) - .to_string(), - ) - .send() - .await? - .json() - .await - } - - pub async fn sign_out(username: &str, password: &str) -> Result<(), reqwest::Error> { - let client = reqwest::Client::new(); - - client - .post("https://authserver.mojang.com/signout") - .header(reqwest::header::CONTENT_TYPE, "application/json") - .body( - serde_json::json!( - { - "username": username, - "password": password - } - ) - .to_string(), - ) - .send() - .await?; - - Ok(()) - } - - pub async fn validate(access_token: &str, client_token: &str) -> Result<(), reqwest::Error> { - let client = reqwest::Client::new(); - - client - .post("https://authserver.mojang.com/validate") - .header(reqwest::header::CONTENT_TYPE, "application/json") - .body( - serde_json::json!( - { - "accessToken": access_token, - "clientToken": client_token - } - ) - .to_string(), - ) - .send() - .await?; - - Ok(()) - } - - pub async fn invalidate(access_token: &str, client_token: &str) -> Result<(), reqwest::Error> { - let client = reqwest::Client::new(); - - client - .post("https://authserver.mojang.com/invalidate") - .header(reqwest::header::CONTENT_TYPE, "application/json") - .body( - serde_json::json!( - { - "accessToken": access_token, - "clientToken": client_token - } - ) - .to_string(), - ) - .send() - .await?; - - Ok(()) - } - - #[derive(Debug, Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct RefreshResponse { - pub user: Option, - pub client_token: Uuid, - pub access_token: String, - pub selected_profile: Option, - } - - pub async fn refresh( - access_token: &str, - client_token: &str, - selected_profile: &GameProfile, - request_user: bool, - ) -> Result { - let client = reqwest::Client::new(); - - client - .post("https://authserver.mojang.com/refresh") - .header(reqwest::header::CONTENT_TYPE, "application/json") - .body( - serde_json::json!( - { - "accessToken": access_token, - "clientToken": client_token, - "selectedProfile": { - "id": selected_profile.id, - "name": selected_profile.name, - }, - "requestUser": request_user, - } - ) - .to_string(), - ) - .send() - .await? - .json() - .await - } -} - -pub mod provider { - use crate::launcher::auth::api::login; - use crate::launcher::LauncherError; - use uuid::Uuid; - - #[derive(Debug)] - /// The credentials of a user - pub struct Credentials { - /// The user UUID the credentials belong to - pub id: Uuid, - /// The username of the user - pub username: String, - /// The access token associated with the credentials - pub access_token: String, - } - - impl Credentials { - /// Gets a credentials instance from a user's login - pub async fn from_login(username: &str, password: &str) -> Result { - let login = - login(username, password, true) - .await - .map_err(|err| LauncherError::FetchError { - inner: err, - item: "authentication credentials".to_string(), - })?; - - let profile = login.selected_profile.unwrap(); - - Ok(Credentials { - id: profile.id, - username: profile.name, - access_token: login.access_token, - }) - } - } +//! Authentication flow +// TODO: Implement authentication +#[derive(Debug)] +pub struct Credentials { + pub id: uuid::Uuid, + pub username: String, + pub access_token: String, } diff --git a/theseus/src/launcher/download.rs b/theseus/src/launcher/download.rs index 0e0794e3..22459475 100644 --- a/theseus/src/launcher/download.rs +++ b/theseus/src/launcher/download.rs @@ -1,362 +1,282 @@ +//! Downloader for Minecraft data + use crate::{ - data::{DataError, Settings}, - launcher::LauncherError, + state::State, + util::{fetch::*, platform::OsExt}, }; -use daedalus::get_path_from_artifact; -use daedalus::minecraft::{ - fetch_assets_index, fetch_version_info, Asset, AssetsIndex, DownloadType, - Library, Os, Version, VersionInfo, -}; -use daedalus::modded::{ - fetch_partial_version, merge_partial_version, LoaderVersion, -}; -use futures::future; -use std::path::Path; -use std::time::Duration; -use tokio::{ - fs::File, - io::AsyncWriteExt, - sync::{OnceCell, Semaphore}, +use daedalus::{ + self as d, + minecraft::{ + Asset, AssetsIndex, Library, Os, Version as GameVersion, + VersionInfo as GameVersionInfo, + }, + modded::LoaderVersion, }; +use futures::prelude::*; +use std::sync::Arc; +use tokio::{fs, sync::OnceCell}; -static DOWNLOADS_SEMAPHORE: OnceCell = OnceCell::const_new(); +pub async fn download_minecraft( + st: &State, + version: &GameVersionInfo, +) -> crate::Result<()> { + log::info!("Downloading Minecraft version {}", version.id); + let assets_index = download_assets_index(st, version).await?; -pub async fn init() -> Result<(), DataError> { - DOWNLOADS_SEMAPHORE - .get_or_try_init(|| async { - let settings = Settings::get().await?; - Ok::<_, DataError>(Semaphore::new( - settings.max_concurrent_downloads, - )) - }) - .await?; + tokio::try_join! { + download_client(st, version), + download_assets(st, version.assets == "legacy", &assets_index), + download_libraries(st, version.libraries.as_slice(), &version.id) + }?; + log::info!("Done downloading Minecraft!"); Ok(()) } pub async fn download_version_info( - client_path: &Path, - version: &Version, - loader_version: Option<&LoaderVersion>, -) -> Result { - let id = match loader_version { - Some(x) => &x.id, - None => &version.id, - }; + st: &State, + version: &GameVersion, + loader: Option<&LoaderVersion>, +) -> crate::Result { + let version_id = loader.map_or(&version.id, |it| &it.id); + log::debug!("Loading version info for Minecraft {version_id}"); + let path = st + .directories + .version_dir(version_id) + .join(format!("{version_id}.json")); - let mut path = client_path.join(id); - path.push(&format!("{id}.json")); - - if path.exists() { - let contents = std::fs::read_to_string(path)?; - Ok(serde_json::from_str(&contents)?) + let res = if path.exists() { + fs::read(path) + .err_into::() + .await + .and_then(|ref it| Ok(serde_json::from_slice(it)?)) } else { - let mut info = fetch_version_info(version).await?; + log::info!("Downloading version info for version {}", &version.id); + let mut info = d::minecraft::fetch_version_info(version).await?; - if let Some(loader_version) = loader_version { - let partial = fetch_partial_version(&loader_version.url).await?; - info = merge_partial_version(partial, info); - info.id = loader_version.id.clone(); + if let Some(loader) = loader { + let partial = d::modded::fetch_partial_version(&loader.url).await?; + info = d::modded::merge_partial_version(partial, info); + info.id = loader.id.clone(); } - let info_s = serde_json::to_string(&info)?; - save_file(&path, &bytes::Bytes::from(info_s)).await?; + let permit = st.io_semaphore.acquire().await.unwrap(); + write(&path, &serde_json::to_vec(&info)?, &permit).await?; Ok(info) - } + }?; + + log::debug!("Loaded version info for Minecraft {version_id}"); + Ok(res) } pub async fn download_client( - client_path: &Path, - version_info: &VersionInfo, -) -> Result<(), LauncherError> { - let version = &version_info.id; + st: &State, + version_info: &GameVersionInfo, +) -> crate::Result<()> { + let ref version = version_info.id; + log::debug!("Locating client for version {version}"); let client_download = version_info .downloads - .get(&DownloadType::Client) - .ok_or_else(|| { - LauncherError::InvalidInput(format!( - "Version {version} does not have any client downloads" - )) - })?; + .get(&d::minecraft::DownloadType::Client) + .ok_or(crate::Error::LauncherError(format!( + "No client downloads exist for version {version}" + )))?; + let path = st + .directories + .version_dir(version) + .join(format!("{version}.jar")); - let mut path = client_path.join(version); - path.push(&format!("{version}.jar")); + if !path.exists() { + let permit = st.io_semaphore.acquire().await.unwrap(); + let bytes = + fetch(&client_download.url, Some(&client_download.sha1), &permit) + .await?; + write(&path, &bytes, &permit).await?; + log::info!("Fetched client version {version}"); + } - save_and_download_file( - &path, - &client_download.url, - Some(&client_download.sha1), - ) - .await?; + log::debug!("Client loaded for version {version}!"); Ok(()) } pub async fn download_assets_index( - assets_path: &Path, - version: &VersionInfo, -) -> Result { - let path = - assets_path.join(format!("indexes/{}.json", &version.asset_index.id)); + st: &State, + version: &GameVersionInfo, +) -> crate::Result { + log::debug!("Loading assets index"); + let path = st + .directories + .assets_index_dir() + .join(format!("{}.json", &version.asset_index.id)); - if path.exists() { - let content = std::fs::read_to_string(path)?; - Ok(serde_json::from_str(&content)?) + let res = if path.exists() { + fs::read(path) + .err_into::() + .await + .and_then(|ref it| Ok(serde_json::from_slice(it)?)) } else { - let index = fetch_assets_index(version).await?; - - save_file(&path, &bytes::Bytes::from(serde_json::to_string(&index)?)) - .await?; - + let index = d::minecraft::fetch_assets_index(version).await?; + let permit = st.io_semaphore.acquire().await.unwrap(); + write(&path, &serde_json::to_vec(&index)?, &permit).await?; + log::info!("Fetched assets index"); Ok(index) - } + }?; + + log::debug!("Assets index successfully loaded!"); + Ok(res) } pub async fn download_assets( - assets_path: &Path, - legacy_path: Option<&Path>, + st: &State, + with_legacy: bool, index: &AssetsIndex, -) -> Result<(), LauncherError> { - future::join_all(index.objects.iter().map(|(name, asset)| { - download_asset(assets_path, legacy_path, name, asset) - })) - .await - .into_iter() - .collect::, LauncherError>>()?; +) -> crate::Result<()> { + log::debug!("Loading assets"); - Ok(()) -} + stream::iter(index.objects.iter()) + .map(Ok::<(&String, &Asset), crate::Error>) + .try_for_each_concurrent(None, |(name, asset)| async move { + let ref hash = asset.hash; + let resource_path = st.directories.object_dir(hash); + let url = format!( + "https://resources.download.minecraft.net/{sub_hash}/{hash}", + sub_hash = &hash[..2] + ); -async fn download_asset( - assets_path: &Path, - legacy_path: Option<&Path>, - name: &str, - asset: &Asset, -) -> Result<(), LauncherError> { - let hash = &asset.hash; - let sub_hash = &hash[..2]; + let fetch_cell = OnceCell::::new(); + tokio::try_join! { + async { + if !resource_path.exists() { + let permit = st.io_semaphore.acquire().await.unwrap(); + let resource = fetch_cell + .get_or_try_init(|| fetch(&url, Some(hash), &permit)) + .await?; + write(&resource_path, &resource, &permit).await?; + log::info!("Fetched asset with hash {hash}"); + } + Ok::<_, crate::Error>(()) + }, + async { + if with_legacy { + let permit = st.io_semaphore.acquire().await.unwrap(); + let resource = fetch_cell + .get_or_try_init(|| fetch(&url, Some(hash), &permit)) + .await?; + let resource_path = st.directories.legacy_assets_dir().join( + name.replace('/', &String::from(std::path::MAIN_SEPARATOR)) + ); + write(&resource_path, &resource, &permit).await?; + log::info!("Fetched legacy asset with hash {hash}"); + } + Ok::<_, crate::Error>(()) + }, + }?; - let mut resource_path = assets_path.join("objects"); - resource_path.push(sub_hash); - resource_path.push(hash); - - let url = - format!("https://resources.download.minecraft.net/{sub_hash}/{hash}"); - - let resource = - save_and_download_file(&resource_path, &url, Some(hash)).await?; - - if let Some(legacy_path) = legacy_path { - let resource_path = legacy_path - .join(name.replace('/', &std::path::MAIN_SEPARATOR.to_string())); - save_file(resource_path.as_path(), &resource).await?; - } + log::debug!("Loaded asset with hash {hash}"); + Ok(()) + }).await?; + log::debug!("Done loading assets!"); Ok(()) } pub async fn download_libraries( - libraries_path: &Path, - natives_path: &Path, + st: &State, libraries: &[Library], -) -> Result<(), LauncherError> { - future::join_all(libraries.iter().map(|library| { - download_library(libraries_path, natives_path, library) - })) - .await - .into_iter() - .collect::, LauncherError>>()?; + version: &str, +) -> crate::Result<()> { + log::debug!("Loading libraries"); + let (libraries_dir, natives_dir) = ( + Arc::new(st.directories.libraries_dir()), + Arc::new(st.directories.version_natives_dir(version)), + ); - Ok(()) -} + tokio::try_join! { + fs::create_dir_all(st.directories.libraries_dir()), + fs::create_dir_all(st.directories.version_natives_dir(version)) + }?; -async fn download_library( - libraries_path: &Path, - natives_path: &Path, - library: &Library, -) -> Result<(), LauncherError> { - if let Some(rules) = &library.rules { - if !super::rules::parse_rules(rules) { - return Ok(()); - } - } + stream::iter(libraries.iter()) + .map(Ok::<&Library, crate::Error>) + .try_for_each_concurrent(None, |library| async move { + if let Some(rules) = &library.rules { + if !rules.iter().all(super::parse_rule) { + return Ok(()); + } + } + tokio::try_join! { + async { + let artifact_path = d::get_path_from_artifact(&library.name)?; + let path = st.directories.libraries_dir().join(&artifact_path); - future::try_join( - download_library_jar(libraries_path, library), - download_native(natives_path, library), - ) - .await?; + match library.downloads { + _ if path.exists() => Ok(()), + Some(d::minecraft::LibraryDownloads { + artifact: Some(ref artifact), + .. + }) => { + let permit = st.io_semaphore.acquire().await.unwrap(); + let bytes = fetch(&artifact.url, Some(&artifact.sha1), &permit) + .await?; + write(&path, &bytes, &permit).await?; + log::info!("Fetched library {}", &library.name); + Ok::<_, crate::Error>(()) + } + None => { + let url = [ + library + .url + .as_deref() + .unwrap_or("https://libraries.minecraft.net"), + &artifact_path + ].concat(); - Ok(()) -} + let permit = st.io_semaphore.acquire().await.unwrap(); + let bytes = fetch(&url, None, &permit).await?; + write(&path, &bytes, &permit).await?; + log::info!("Fetched library {}", &library.name); + Ok::<_, crate::Error>(()) + } + _ => Ok(()) + } + }, + async { + // HACK: pseudo try block using or else + if let Some((os_key, classifiers)) = None.or_else(|| Some(( + library + .natives + .as_ref()? + .get(&Os::native())?, + library + .downloads + .as_ref()? + .classifiers + .as_ref()? + ))) { + let parsed_key = os_key.replace( + "${arch}", + crate::util::platform::ARCH_WIDTH, + ); -async fn download_library_jar( - libraries_path: &Path, - library: &Library, -) -> Result<(), LauncherError> { - let artifact_path = get_path_from_artifact(&library.name)?; - let path = libraries_path.join(&artifact_path); - - if let Some(downloads) = &library.downloads { - if let Some(library) = &downloads.artifact { - save_and_download_file(&path, &library.url, Some(&library.sha1)) - .await?; - } - } else { - let url = format!( - "{}{artifact_path}", - library - .url - .as_deref() - .unwrap_or("https://libraries.minecraft.net/"), - ); - save_and_download_file(&path, &url, None).await?; - } - - Ok(()) -} - -async fn download_native( - natives_path: &Path, - library: &Library, -) -> Result<(), LauncherError> { - use daedalus::minecraft::LibraryDownload; - use std::collections::HashMap; - - // Try blocks in stable Rust when? - let optional_cascade = - || -> Option<(&String, &HashMap)> { - let os_key = library.natives.as_ref()?.get(&get_os())?; - let classifiers = - library.downloads.as_ref()?.classifiers.as_ref()?; - Some((os_key, classifiers)) - }; - - if let Some((os_key, classifiers)) = optional_cascade() { - #[cfg(target_pointer_width = "64")] - let parsed_key = os_key.replace("${arch}", "64"); - #[cfg(target_pointer_width = "32")] - let parsed_key = os_key.replace("${arch}", "32"); - - if let Some(native) = classifiers.get(&parsed_key) { - let file = download_file(&native.url, Some(&native.sha1)).await?; - - let reader = std::io::Cursor::new(&file); - - let mut archive = zip::ZipArchive::new(reader).unwrap(); - archive.extract(natives_path).unwrap(); - } - } - Ok(()) -} - -async fn save_and_download_file( - path: &Path, - url: &str, - sha1: Option<&str>, -) -> Result { - match std::fs::read(path) { - Ok(bytes) => Ok(bytes::Bytes::from(bytes)), - Err(_) => { - let file = download_file(url, sha1).await?; - save_file(path, &file).await?; - Ok(file) - } - } -} - -async fn save_file(path: &Path, bytes: &bytes::Bytes) -> std::io::Result<()> { - let _save_permit = DOWNLOADS_SEMAPHORE - .get() - .expect("File operation semaphore not initialized!") - .acquire() - .await - .unwrap(); - if let Some(parent) = path.parent() { - tokio::fs::create_dir_all(parent).await?; - } - - let mut file = File::create(path).await?; - file.write_all(bytes).await?; - Ok(()) -} - -pub fn get_os() -> Os { - match std::env::consts::OS { - "windows" => Os::Windows, - "macos" => Os::Osx, - "linux" => Os::Linux, - _ => Os::Unknown, - } -} - -pub async fn download_file( - url: &str, - sha1: Option<&str>, -) -> Result { - let _download_permit = DOWNLOADS_SEMAPHORE - .get() - .expect("File operation semaphore not initialized!") - .acquire() - .await - .unwrap(); - - let client = reqwest::Client::builder() - .tcp_keepalive(Some(Duration::from_secs(10))) - .build() - .map_err(|err| LauncherError::FetchError { - inner: err, - item: url.to_string(), - })?; - - for attempt in 1..=4 { - let result = client.get(url).send().await; - - match result { - Ok(x) => { - let bytes = x.bytes().await; - - if let Ok(bytes) = bytes { - if let Some(sha1) = sha1 { - if &get_hash(bytes.clone()).await? != sha1 { - if attempt <= 3 { - continue; - } else { - return Err(LauncherError::ChecksumFailure { - hash: sha1.to_string(), - url: url.to_string(), - tries: attempt, - }); - } + if let Some(native) = classifiers.get(&parsed_key) { + let permit = st.io_semaphore.acquire().await.unwrap(); + let data = fetch(&native.url, Some(&native.sha1), &permit).await?; + let reader = std::io::Cursor::new(&data); + let mut archive = zip::ZipArchive::new(reader).unwrap(); + archive.extract(&st.directories.version_natives_dir(version)).unwrap(); + log::info!("Fetched native {}", &library.name); } } - return Ok(bytes); - } else if attempt <= 3 { - continue; - } else if let Err(err) = bytes { - return Err(LauncherError::FetchError { - inner: err, - item: url.to_string(), - }); + Ok(()) } - } - Err(_) if attempt <= 3 => continue, - Err(err) => { - return Err(LauncherError::FetchError { - inner: err, - item: url.to_string(), - }) - } + }?; + + log::debug!("Loaded library {}", library.name); + Ok(()) } - } - unreachable!() -} + ).await?; -/// Computes a checksum of the input bytes -async fn get_hash(bytes: bytes::Bytes) -> Result { - let hash = - tokio::task::spawn_blocking(|| sha1::Sha1::from(bytes).hexdigest()) - .await?; - - Ok(hash) + log::debug!("Done loading libraries!"); + Ok(()) } diff --git a/theseus/src/launcher/mod.rs b/theseus/src/launcher/mod.rs index 2d54c533..93da54c3 100644 --- a/theseus/src/launcher/mod.rs +++ b/theseus/src/launcher/mod.rs @@ -1,205 +1,116 @@ -use daedalus::minecraft::{ArgumentType, VersionInfo}; -use daedalus::modded::LoaderVersion; -use serde::{Deserialize, Serialize}; +//! Logic for launching Minecraft +use crate::state as st; +use daedalus as d; use std::{path::Path, process::Stdio}; -use thiserror::Error; use tokio::process::{Child, Command}; -pub use crate::launcher::auth::provider::Credentials; - mod args; -pub mod auth; + +mod auth; +pub use auth::Credentials; + mod download; -mod rules; -pub(crate) use download::init as init_download_semaphore; +pub fn parse_rule(rule: &d::minecraft::Rule) -> bool { + use d::minecraft::{Rule, RuleAction}; -#[derive(Error, Debug)] -pub enum LauncherError { - #[error("Failed to validate file checksum at url {url} with hash {hash} after {tries} tries")] - ChecksumFailure { - hash: String, - url: String, - tries: u32, - }, + let res = match rule { + Rule { + os: Some(ref os), .. + } => crate::util::platform::os_rule(os), + Rule { + features: Some(ref features), + .. + } => features.has_demo_resolution.unwrap_or(false), + _ => true, + }; - #[error("Failed to run processor: {0}")] - ProcessorError(String), - - #[error("Invalid input: {0}")] - InvalidInput(String), - - #[error("Error while managing asynchronous tasks")] - TaskError(#[from] tokio::task::JoinError), - - #[error("Error while reading/writing to the disk: {0}")] - IoError(#[from] std::io::Error), - - #[error("Error while spawning child process {process}")] - ProcessError { - inner: std::io::Error, - process: String, - }, - - #[error("Error while deserializing JSON")] - SerdeError(#[from] serde_json::Error), - - #[error("Unable to fetch {item}")] - FetchError { inner: reqwest::Error, item: String }, - - #[error("{0}")] - ParseError(String), - - #[error("Error while fetching metadata: {0}")] - DaedalusError(#[from] daedalus::Error), - - #[error("Error while reading metadata: {0}")] - MetaError(#[from] crate::data::DataError), - - #[error("Java error: {0}")] - JavaError(String), - - #[error("Command exited with non-zero exit code: {0}")] - ExitError(i32), -} - -// TODO: this probably should be in crate::data -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum ModLoader { - Vanilla, - Forge, - Fabric, -} - -impl Default for ModLoader { - fn default() -> Self { - ModLoader::Vanilla + match rule.action { + RuleAction::Allow => res, + RuleAction::Disallow => !res, } } -impl std::fmt::Display for ModLoader { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let repr = match self { - &Self::Vanilla => "Vanilla", - &Self::Forge => "Forge", - &Self::Fabric => "Fabric", - }; - - f.write_str(repr) +macro_rules! processor_rules { + ($dest:expr; $($name:literal : client => $client:expr, server => $server:expr;)+) => { + $(std::collections::HashMap::insert( + $dest, + String::from($name), + daedalus::modded::SidedDataEntry { + client: String::from($client), + server: String::from($server), + }, + );)+ } } pub async fn launch_minecraft( game_version: &str, - loader_version: &Option, - root_dir: &Path, - java: &Path, - java_args: &Vec, + loader_version: &Option, + instance_path: &Path, + java_install: &Path, + java_args: &[String], wrapper: &Option, - memory: &crate::data::profiles::MemorySettings, - resolution: &crate::data::profiles::WindowSize, - credentials: &Credentials, -) -> Result { - let (metadata, settings) = futures::try_join! { - crate::data::Metadata::get(), - crate::data::Settings::get(), - }?; - let root_dir = root_dir.canonicalize()?; - let metadata_dir = &settings.metadata_dir; + memory: &st::MemorySettings, + resolution: &st::WindowSize, + credentials: &auth::Credentials, +) -> crate::Result { + let state = st::State::get().await?; + let instance_path = instance_path.canonicalize()?; - let ( - versions_path, - libraries_path, - assets_path, - legacy_assets_path, - natives_path, - ) = ( - metadata_dir.join("versions"), - metadata_dir.join("libraries"), - metadata_dir.join("assets"), - metadata_dir.join("resources"), - metadata_dir.join("natives"), - ); - - let version = metadata + let version = state + .metadata .minecraft .versions .iter() .find(|it| it.id == game_version) - .ok_or_else(|| { - LauncherError::InvalidInput(format!( - "Invalid game version: {game_version}", - )) - })?; + .ok_or(crate::Error::LauncherError(format!( + "Invalid game version: {game_version}" + )))?; let version_jar = loader_version .as_ref() .map_or(version.id.clone(), |it| it.id.clone()); - let mut version = download::download_version_info( - &versions_path, - version, + let mut version_info = download::download_version_info( + &state, + &version, loader_version.as_ref(), ) .await?; - let client_path = versions_path - .join(&version.id) - .join(format!("{}.jar", &version_jar)); - let version_natives_path = natives_path.join(&version.id); + let client_path = state + .directories + .version_dir(&version.id) + .join(format!("{version_jar}.jar")); - download_minecraft( - &version, - &versions_path, - &assets_path, - &legacy_assets_path, - &libraries_path, - &version_natives_path, - ) - .await?; + download::download_minecraft(&state, &version_info).await?; + st::State::sync().await?; - if let Some(processors) = &version.processors { - if let Some(ref mut data) = version.data { - data.insert( - "SIDE".to_string(), - daedalus::modded::SidedDataEntry { - client: "client".to_string(), - server: "".to_string(), - }, - ); - data.insert( - "MINECRAFT_JAR".to_string(), - daedalus::modded::SidedDataEntry { - client: client_path.to_string_lossy().to_string(), - server: "".to_string(), - }, - ); - data.insert( - "MINECRAFT_VERSION".to_string(), - daedalus::modded::SidedDataEntry { - client: game_version.to_string(), - server: "".to_string(), - }, - ); - data.insert( - "ROOT".to_string(), - daedalus::modded::SidedDataEntry { - client: root_dir.to_string_lossy().to_string(), - server: "".to_string(), - }, - ); - data.insert( - "LIBRARY_DIR".to_string(), - daedalus::modded::SidedDataEntry { - client: libraries_path.to_string_lossy().to_string(), - server: "".to_string(), - }, - ); + if let Some(processors) = &version_info.processors { + if let Some(ref mut data) = version_info.data { + processor_rules! { + data; + "SIDE": + client => "client", + server => ""; + "MINECRAFT_JAR" : + client => client_path.to_string_lossy(), + server => ""; + "MINECRAFT_VERSION": + client => game_version, + server => ""; + "ROOT": + client => instance_path.to_string_lossy(), + server => ""; + "LIBRARY_DIR": + client => state.directories.libraries_dir().to_string_lossy(), + server => ""; + } for processor in processors { if let Some(sides) = &processor.sides { - if !sides.contains(&"client".to_string()) { + if !sides.contains(&String::from("client")) { continue; } } @@ -209,120 +120,93 @@ pub async fn launch_minecraft( let child = Command::new("java") .arg("-cp") - .arg(args::get_class_paths_jar(&libraries_path, &cp)?) + .arg(args::get_class_paths_jar( + &state.directories.libraries_dir(), + &cp, + )?) .arg( args::get_processor_main_class(args::get_lib_path( - &libraries_path, + &state.directories.libraries_dir(), &processor.jar, )?) .await? .ok_or_else(|| { - LauncherError::ProcessorError(format!( + crate::Error::LauncherError(format!( "Could not find processor main class for {}", processor.jar )) })?, ) .args(args::get_processor_arguments( - &libraries_path, + &state.directories.libraries_dir(), &processor.args, data, )?) .output() .await - .map_err(|err| LauncherError::ProcessError { - inner: err, - process: "java".to_string(), + .map_err(|err| { + crate::Error::LauncherError(format!( + "Error running processor: {err}", + )) })?; if !child.status.success() { - return Err(LauncherError::ProcessorError( - String::from_utf8_lossy(&child.stderr).to_string(), - )); + return Err(crate::Error::LauncherError(format!( + "Processor error: {}", + String::from_utf8_lossy(&child.stderr) + ))); } } } } - let arguments = version.arguments.clone().unwrap_or_default(); + let args = version_info.arguments.clone().unwrap_or_default(); let mut command = match wrapper { Some(hook) => { let mut cmd = Command::new(hook); - cmd.arg(java); + cmd.arg(java_install); cmd } - None => Command::new(java.to_string_lossy().to_string()), + None => Command::new(String::from(java_install.to_string_lossy())), }; command .args(args::get_jvm_arguments( - arguments.get(&ArgumentType::Jvm).map(|x| x.as_slice()), - &version_natives_path, - &libraries_path, + args.get(&d::minecraft::ArgumentType::Jvm) + .map(|x| x.as_slice()), + &state.directories.version_natives_dir(&version.id), + &state.directories.libraries_dir(), &args::get_class_paths( - &libraries_path, - version.libraries.as_slice(), + &state.directories.libraries_dir(), + version_info.libraries.as_slice(), &client_path, )?, &version_jar, *memory, - java_args.clone(), + Vec::from(java_args), )?) - .arg(version.main_class.clone()) + .arg(version_info.main_class.clone()) .args(args::get_minecraft_arguments( - arguments.get(&ArgumentType::Game).map(|x| x.as_slice()), - version.minecraft_arguments.as_deref(), + args.get(&d::minecraft::ArgumentType::Game) + .map(|x| x.as_slice()), + version_info.minecraft_arguments.as_deref(), credentials, &version.id, - &version.asset_index.id, - &root_dir, - &assets_path, + &version_info.asset_index.id, + &instance_path, + &state.directories.assets_dir(), &version.type_, *resolution, )?) - .current_dir(root_dir.clone()) + .current_dir(instance_path.clone()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()); - command.spawn().map_err(|err| LauncherError::ProcessError { - inner: err, - process: format!("minecraft-{} @ {}", &version.id, root_dir.display()), + command.spawn().map_err(|err| { + crate::Error::LauncherError(format!( + "Error running Minecraft (minecraft-{} @ {}): {err}", + &version.id, + instance_path.display() + )) }) } - -pub async fn download_minecraft( - version: &VersionInfo, - versions_dir: &Path, - assets_dir: &Path, - legacy_assets_dir: &Path, - libraries_dir: &Path, - natives_dir: &Path, -) -> Result<(), LauncherError> { - let assets_index = - download::download_assets_index(assets_dir, version).await?; - - let (a, b, c) = futures::future::join3( - download::download_client(versions_dir, version), - download::download_assets( - assets_dir, - if version.assets == "legacy" { - Some(legacy_assets_dir) - } else { - None - }, - &assets_index, - ), - download::download_libraries( - libraries_dir, - natives_dir, - version.libraries.as_slice(), - ), - ) - .await; - - a?; - b?; - c?; - - Ok(()) -} diff --git a/theseus/src/launcher/rules.rs b/theseus/src/launcher/rules.rs deleted file mode 100644 index de4f588c..00000000 --- a/theseus/src/launcher/rules.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::launcher::download::get_os; -use daedalus::minecraft::{OsRule, Rule, RuleAction}; -use regex::Regex; - -pub fn parse_rules(rules: &[Rule]) -> bool { - rules.iter().all(|x| parse_rule(x)) -} - -pub fn parse_rule(rule: &Rule) -> bool { - let result = if let Some(os) = &rule.os { - parse_os_rule(os) - } else if let Some(features) = &rule.features { - features.has_demo_resolution.unwrap_or(false) - } else { - true - }; - - match rule.action { - RuleAction::Allow => result, - RuleAction::Disallow => !result, - } -} - -pub fn parse_os_rule(rule: &OsRule) -> bool { - if let Some(arch) = &rule.arch { - match arch.as_str() { - "x86" => { - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - return false; - } - "arm" => { - #[cfg(not(target_arch = "arm"))] - return false; - } - _ => {} - } - } - - if let Some(name) = &rule.name { - if &get_os() != name { - return false; - } - } - if let Some(version) = &rule.version { - let regex = Regex::new(version.as_str()); - - if let Ok(regex) = regex { - if !regex.is_match(&sys_info::os_release().unwrap_or_default()) { - return false; - } - } - } - - true -} diff --git a/theseus/src/lib.rs b/theseus/src/lib.rs index 7b4265d5..80baede2 100644 --- a/theseus/src/lib.rs +++ b/theseus/src/lib.rs @@ -1,57 +1,19 @@ -//! # Theseus -//! -//! Theseus is a library which provides utilities for launching minecraft, creating Modrinth mod packs, -//! and launching Modrinth mod packs +/*! +# Theseus +Theseus is a library which provides utilities for launching minecraft, creating Modrinth mod packs, +and launching Modrinth mod packs +*/ #![warn(unused_import_braces, missing_debug_implementations)] +#![deny(unused_must_use)] -// TODO: make non-hardcoded -lazy_static::lazy_static! { - static ref LAUNCHER_WORK_DIR: std::path::PathBuf = dirs::config_dir().expect("Could not find config dir").join("theseus"); -} - -pub mod data; -pub mod launcher; -pub mod modpack; +mod api; +mod config; +mod error; +mod launcher; +mod state; mod util; -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Launcher error: {0}")] - LauncherError(#[from] launcher::LauncherError), - - #[error("Modpack error: {0}")] - ModpackError(#[from] modpack::ModpackError), - - #[error("Data error: {0}")] - DaedalusError(#[from] data::DataError), -} - -pub async fn init() -> Result<(), Error> { - tokio::fs::create_dir_all(LAUNCHER_WORK_DIR.as_path()) - .await - .expect("Unable to create launcher root directory!"); - - use crate::data::*; - Metadata::init().await?; - - Settings::init().await?; - - tokio::try_join! { - launcher::init_download_semaphore(), - Profiles::init(), - }?; - - Ok(()) -} - -pub async fn save() -> Result<(), Error> { - use crate::data::*; - - tokio::try_join! { - Settings::save(), - Profiles::save(), - }?; - - Ok(()) -} +pub use api::*; +pub use error::*; +pub use state::State; diff --git a/theseus/src/modpack/manifest.rs b/theseus/src/modpack/manifest.rs deleted file mode 100644 index 85e6c16c..00000000 --- a/theseus/src/modpack/manifest.rs +++ /dev/null @@ -1,446 +0,0 @@ -use std::path::PathBuf; - -use std::convert::TryFrom; - -use crate::launcher::ModLoader; - -use super::pack::ModpackGame; -use super::{pack, ModpackError, ModpackResult}; -use serde::{Deserialize, Serialize}; - -pub const DEFAULT_FORMAT_VERSION: u32 = 1; -const MODRINTH_GAMEDATA_URL: &str = "https://staging-cdn.modrinth.com/gamedata"; - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct Manifest { - pub format_version: u32, - pub game: String, - pub version_id: String, - pub name: String, - pub summary: Option, - pub files: Vec, - pub dependencies: ManifestDeps, -} - -impl TryFrom for pack::Modpack { - type Error = ModpackError; - - fn try_from(manifest: Manifest) -> Result { - let files = manifest - .files - .into_iter() - .map(pack::ModpackFile::try_from) - .collect::>()?; - - Ok(Self { - name: manifest.name, - version: manifest.version_id, - summary: manifest.summary, - game: ModpackGame::from(manifest.dependencies), - files, - }) - } -} - -fn get_loader_version(loader: ModLoader, version: &str) -> ModpackResult { - let source = match loader { - ModLoader::Vanilla => Err(ModpackError::VersionError(String::from( - "Attempted to get mod loader version of Vanilla", - ))), - ModLoader::Forge => Ok(format!("{MODRINTH_GAMEDATA_URL}/forge/v0/manifest.json")), - ModLoader::Fabric => Ok(format!("{MODRINTH_GAMEDATA_URL}/fabric/v0/manifest.json")), - }?; - let manifest = futures::executor::block_on(daedalus::modded::fetch_manifest(&source))?; - - let version = manifest - .game_versions - .iter() - .find(|&it| it.id == version) - .map(|x| x.loaders.first()) - .flatten() - .ok_or_else(|| { - ModpackError::VersionError(format!( - "No versions of modloader {loader:?} exist for Minecraft {version}", - )) - })?; - Ok(version.id.clone()) -} - -impl TryFrom for Manifest { - type Error = ModpackError; - - fn try_from(pack: pack::Modpack) -> Result { - let pack::Modpack { - game, - version, - name, - summary, - files, - } = pack; - - let game_name = match &game { - ModpackGame::Minecraft(..) => "minecraft".into(), - }; - - let files: Vec<_> = files.into_iter().map(ManifestFile::from).collect(); - - Ok(Manifest { - format_version: DEFAULT_FORMAT_VERSION, - game: game_name, - version_id: version, - name, - summary, - files, - dependencies: ManifestDeps::try_from(game)?, - }) - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct ManifestFile { - pub path: PathBuf, - pub hashes: Option, - #[serde(default)] - pub env: ManifestEnvs, - pub downloads: Vec, -} - -impl TryFrom for pack::ModpackFile { - type Error = ModpackError; - - fn try_from(file: ManifestFile) -> Result { - Ok(Self { - path: file.path, - hashes: file.hashes.map(pack::ModpackFileHashes::from), - env: pack::ModpackEnv::try_from(file.env)?, - downloads: file.downloads.into_iter().collect(), - }) - } -} - -impl From for ManifestFile { - fn from(file: pack::ModpackFile) -> Self { - Self { - path: file.path, - hashes: file.hashes.map(ManifestHashes::from), - env: file.env.into(), - downloads: file.downloads.into_iter().collect(), - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct ManifestHashes { - pub sha1: String, -} - -impl From for pack::ModpackFileHashes { - fn from(hashes: ManifestHashes) -> Self { - Self { sha1: hashes.sha1 } - } -} - -impl From for ManifestHashes { - fn from(hashes: pack::ModpackFileHashes) -> Self { - Self { sha1: hashes.sha1 } - } -} - -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)] -pub struct ManifestEnvs { - pub client: ManifestEnv, - pub server: ManifestEnv, -} - -impl Default for ManifestEnvs { - fn default() -> Self { - Self { - client: ManifestEnv::Optional, - server: ManifestEnv::Optional, - } - } -} - -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum ManifestEnv { - Required, - Optional, - Unsupported, -} - -impl TryFrom for pack::ModpackEnv { - type Error = ModpackError; - - fn try_from(envs: ManifestEnvs) -> Result { - use ManifestEnv::*; - - match (envs.client, envs.server) { - (Required, Unsupported) => Ok(Self::ClientOnly), - (Unsupported, Required) => Ok(Self::ServerOnly), - (Optional, Optional) => Ok(Self::Both), - _ => Err(ModpackError::FormatError(format!( - "Invalid environment specification: {:?}", - envs - ))), - } - } -} - -impl From for ManifestEnvs { - fn from(envs: pack::ModpackEnv) -> Self { - use super::pack::ModpackEnv::*; - - let (client, server) = match envs { - ClientOnly => (ManifestEnv::Required, ManifestEnv::Unsupported), - ServerOnly => (ManifestEnv::Unsupported, ManifestEnv::Required), - Both => (ManifestEnv::Optional, ManifestEnv::Optional), - }; - - Self { client, server } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -#[serde(untagged)] -pub enum ManifestDeps { - MinecraftFabric { - minecraft: String, - #[serde(rename = "fabric-loader")] - fabric_loader: String, - }, - MinecraftForge { - minecraft: String, - forge: String, - }, - MinecraftVanilla { - minecraft: String, - }, -} - -impl From for pack::ModpackGame { - fn from(deps: ManifestDeps) -> Self { - use ManifestDeps::*; - - match deps { - MinecraftVanilla { minecraft } => Self::Minecraft(minecraft, ModLoader::Vanilla), - MinecraftFabric { minecraft, .. } => Self::Minecraft(minecraft, ModLoader::Fabric), - MinecraftForge { minecraft, .. } => Self::Minecraft(minecraft, ModLoader::Forge), - } - } -} - -impl TryFrom for ManifestDeps { - type Error = ModpackError; - - fn try_from(game: pack::ModpackGame) -> Result { - use super::pack::ModpackGame::*; - Ok(match game { - Minecraft(minecraft, ModLoader::Vanilla) => Self::MinecraftVanilla { minecraft }, - Minecraft(minecraft, ModLoader::Fabric) => Self::MinecraftFabric { - fabric_loader: get_loader_version(ModLoader::Fabric, &minecraft)?, - minecraft, - }, - Minecraft(minecraft, ModLoader::Forge) => Self::MinecraftForge { - forge: get_loader_version(ModLoader::Fabric, &minecraft)?, - minecraft, - }, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parse_simple() -> ModpackResult<()> { - const PACK_JSON: &'static str = r#" - { - "formatVersion": 1, - "game": "minecraft", - "versionId": "deadbeef", - "name": "Example Pack", - "files": [], - "dependencies": { - "minecraft": "1.17.1" - } - } - "#; - let expected_manifest = Manifest { - format_version: 1, - game: "minecraft".into(), - version_id: "deadbeef".into(), - name: "Example Pack".into(), - summary: None, - files: vec![], - dependencies: ManifestDeps::MinecraftVanilla { - minecraft: "1.17.1".into(), - }, - }; - let manifest: Manifest = serde_json::from_str(PACK_JSON).expect("Error parsing pack JSON"); - - assert_eq!(expected_manifest, manifest); - Ok(()) - } - - #[test] - fn parse_forge() -> ModpackResult<()> { - const PACK_JSON: &'static str = r#" - { - "formatVersion": 1, - "game": "minecraft", - "versionId": "deadbeef", - "name": "Example Pack", - "files": [ - { - "path": "mods/testmod.jar", - "hashes": { - "sha1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - }, - "downloads": [ - "https://example.com/testmod.jar" - ] - } - ], - "dependencies": { - "minecraft": "1.17.1", - "forge": "37.0.110" - } - } - "#; - let expected_manifest = Manifest { - format_version: 1, - game: "minecraft".into(), - version_id: "deadbeef".into(), - name: "Example Pack".into(), - summary: None, - files: vec![ManifestFile { - path: "mods/testmod.jar".into(), - hashes: Some(ManifestHashes { - sha1: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into(), - }), - env: ManifestEnvs::default(), - downloads: vec!["https://example.com/testmod.jar".into()], - }], - dependencies: ManifestDeps::MinecraftForge { - minecraft: "1.17.1".into(), - forge: "37.0.110".into(), - }, - }; - let manifest: Manifest = serde_json::from_str(PACK_JSON).expect("Error parsing pack JSON"); - - assert_eq!(expected_manifest, manifest); - Ok(()) - } - - #[test] - fn parse_fabric() -> ModpackResult<()> { - const PACK_JSON: &'static str = r#" - { - "formatVersion": 1, - "game": "minecraft", - "versionId": "deadbeef", - "name": "Example Pack", - "files": [ - { - "path": "mods/testmod.jar", - "hashes": { - "sha1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - }, - "downloads": [ - "https://example.com/testmod.jar" - ] - } - ], - "dependencies": { - "minecraft": "1.17.1", - "fabric-loader": "0.9.0" - } - } - "#; - let expected_manifest = Manifest { - format_version: 1, - game: "minecraft".into(), - version_id: "deadbeef".into(), - name: "Example Pack".into(), - summary: None, - files: vec![ManifestFile { - path: "mods/testmod.jar".into(), - hashes: Some(ManifestHashes { - sha1: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into(), - }), - env: ManifestEnvs::default(), - downloads: vec!["https://example.com/testmod.jar".into()], - }], - dependencies: ManifestDeps::MinecraftFabric { - minecraft: "1.17.1".into(), - fabric_loader: "0.9.0".into(), - }, - }; - let manifest: Manifest = serde_json::from_str(PACK_JSON).expect("Error parsing pack JSON"); - - assert_eq!(expected_manifest, manifest); - Ok(()) - } - - #[test] - fn parse_complete() -> ModpackResult<()> { - const PACK_JSON: &'static str = r#" - { - "formatVersion": 1, - "game": "minecraft", - "versionId": "deadbeef", - "name": "Example Pack", - "summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - "files": [ - { - "path": "mods/testmod.jar", - "hashes": { - "sha1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - }, - "env": { - "client": "required", - "server": "unsupported" - }, - "downloads": [ - "https://example.com/testmod.jar" - ] - } - ], - "dependencies": { - "minecraft": "1.17.1", - "forge": "37.0.110" - } - } - "#; - let expected_manifest = Manifest { - format_version: 1, - game: "minecraft".into(), - version_id: "deadbeef".into(), - name: "Example Pack".into(), - summary: Some("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.".into()), - files: vec![ManifestFile { - path: "mods/testmod.jar".into(), - hashes: Some(ManifestHashes { - sha1: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into(), - }), - env: ManifestEnvs { - client: ManifestEnv::Required, - server: ManifestEnv::Unsupported, - }, - downloads: vec!["https://example.com/testmod.jar".into()], - }], - dependencies: ManifestDeps::MinecraftForge { - minecraft: "1.17.1".into(), - forge: "37.0.110".into(), - }, - }; - let manifest: Manifest = serde_json::from_str(PACK_JSON).expect("Error parsing pack JSON"); - - assert_eq!(expected_manifest, manifest); - Ok(()) - } -} diff --git a/theseus/src/modpack/mod.rs b/theseus/src/modpack/mod.rs deleted file mode 100644 index c9655d34..00000000 --- a/theseus/src/modpack/mod.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Provides utilties for downloading and parsing modpacks - -use daedalus::download_file; -use fs_extra::dir::CopyOptions; -use std::{convert::TryFrom, env, io, path::Path}; -use tokio::{fs, try_join}; -use uuid::Uuid; -use zip::ZipArchive; -use zip_extensions::ZipWriterExtensions; - -use self::{ - manifest::Manifest, - pack::{Modpack, ModpackGame}, -}; - -pub mod manifest; -pub mod modrinth_api; -pub mod pack; - -pub const COMPILED_PATH: &str = "compiled/"; -pub const COMPILED_ZIP: &str = "compiled.mrpack"; -pub const MANIFEST_PATH: &str = "modrinth.index.json"; -pub const OVERRIDES_PATH: &str = "overrides/"; -pub const PACK_JSON5_PATH: &str = "modpack.json5"; -const PACK_GITIGNORE: &'static str = const_format::formatcp!( - r#" -{COMPILED_PATH} -{COMPILED_ZIP} -"# -); - -#[derive(thiserror::Error, Debug)] -pub enum ModpackError { - #[error("I/O error while reading modpack: {0}")] - IOError(#[from] io::Error), - - #[error("I/O error while reading modpack: {0}")] - FSExtraError(#[from] fs_extra::error::Error), - - #[error("Error extracting archive: {0}")] - ZipError(#[from] zip::result::ZipError), - - #[error("Invalid modpack format: {0}")] - FormatError(String), - - #[error("Invalid output directory: {0}")] - InvalidDirectory(String), - - #[error("Error parsing manifest: {0}")] - ManifestError(String), - - #[error("Daedalus error: {0}")] - DaedalusError(#[from] daedalus::Error), - - #[error("Error parsing json: {0}")] - JsonError(#[from] serde_json::Error), - - #[error("Error parsing json5: {0}")] - Json5Error(#[from] json5::Error), - - #[error("Error joining futures: {0}")] - JoinError(#[from] tokio::task::JoinError), - - #[error("Versioning Error: {0}")] - VersionError(String), - - #[error("Error downloading file: {0}")] - FetchError(#[from] reqwest::Error), - - #[error("Invalid modpack source: {0} (set the WHITELISTED_MODPACK_DOMAINS environment variable to override)")] - SourceWhitelistError(String), -} - -type ModpackResult = Result; - -/// Realise a modpack from a given URL -pub async fn fetch_modpack( - url: &str, - sha1: Option<&str>, - dest: &Path, - side: pack::ModpackSide, -) -> ModpackResult<()> { - let bytes = download_file(url, sha1).await?; - let mut archive = ZipArchive::new(io::Cursor::new(&bytes as &[u8]))?; - realise_modpack_zip(&mut archive, dest, side).await -} - -/// Realise a given modpack from a zip archive -pub async fn realise_modpack_zip( - archive: &mut ZipArchive, - dest: &Path, - side: pack::ModpackSide, -) -> ModpackResult<()> { - let mut tmp = env::temp_dir(); - tmp.push(format!("theseus-{}/", Uuid::new_v4())); - archive.extract(&tmp)?; - realise_modpack(&tmp, dest, side).await -} - -/// Realise a given modpack into an instance -pub async fn realise_modpack( - dir: &Path, - dest: &Path, - side: pack::ModpackSide, -) -> ModpackResult<()> { - if dest.is_file() { - return Err(ModpackError::InvalidDirectory(String::from( - "Output is not a directory", - ))); - } - if std::fs::read_dir(dest).map_or(false, |it| it.count() != 0) { - return Err(ModpackError::InvalidDirectory(String::from( - "Output directory is non-empty", - ))); - } - if !dest.exists() { - fs::create_dir_all(dest).await?; - } - - // Copy overrides - let overrides = dir.join(OVERRIDES_PATH); - if overrides.is_dir() { - fs_extra::dir::copy(overrides, dest, &CopyOptions::new())?; - } - - // Parse manifest - // NOTE: I'm using standard files here, since Serde does not support async readers - let manifest_path = Some(dir.join(MANIFEST_PATH)) - .filter(|it| it.is_file()) - .ok_or_else(|| { - ModpackError::ManifestError(String::from("Manifest missing or is not a file")) - })?; - let manifest_file = std::fs::File::open(manifest_path)?; - let reader = io::BufReader::new(manifest_file); - - let manifest: Manifest = serde_json::from_reader(reader)?; - let modpack = Modpack::try_from(manifest)?; - - // Realise modpack - modpack.download_files(dest, side).await?; - Ok(()) -} - -pub fn to_pack_json5(pack: &Modpack) -> ModpackResult { - let json5 = json5::to_string(pack)?; - Ok(format!("// This modpack is managed using Theseus. It can be edited using either a Theseus-compatible launcher or manually.\n{json5}")) -} - -pub async fn create_modpack( - name: &str, - game: ModpackGame, - summary: Option<&str>, -) -> ModpackResult<()> { - let output_dir = Path::new("./").join(name); - let pack = Modpack::new(game, "0.1.0", name, summary); - - try_join!( - fs::create_dir(&output_dir), - fs::create_dir(output_dir.join(OVERRIDES_PATH)), - fs::write(output_dir.join(".gitignore"), PACK_GITIGNORE), - fs::write(output_dir.join(PACK_JSON5_PATH), to_pack_json5(&pack)?), - )?; - - Ok(()) -} - -pub async fn compile_modpack(dir: &Path) -> ModpackResult<()> { - let result_dir = dir.join(COMPILED_PATH); - let pack: Modpack = json5::from_str(&fs::read_to_string(dir.join(PACK_JSON5_PATH)).await?)?; - - fs::create_dir(&result_dir).await?; - if dir.join(OVERRIDES_PATH).exists() { - fs_extra::dir::copy( - dir.join(OVERRIDES_PATH), - result_dir.join(OVERRIDES_PATH), - &CopyOptions::new(), - )?; - } - let manifest = Manifest::try_from(pack)?; - fs::write( - result_dir.join(MANIFEST_PATH), - serde_json::to_string(&manifest)?, - ) - .await?; - - let result_zip = fs::File::create(dir.join(COMPILED_ZIP)) - .await? - .into_std() - .await; - let mut zip = zip::ZipWriter::new(&result_zip); - zip.create_from_directory(&result_dir)?; - - Ok(()) -} diff --git a/theseus/src/modpack/modrinth_api.rs b/theseus/src/modpack/modrinth_api.rs deleted file mode 100644 index 17013c64..00000000 --- a/theseus/src/modpack/modrinth_api.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::{collections::HashSet, convert::TryFrom, path::PathBuf}; - -use crate::launcher::ModLoader; - -use super::{ - manifest::{ManifestEnvs, ManifestHashes}, - pack::{ModpackEnv, ModpackFile, ModpackFileHashes, ModpackGame}, - ModpackError, ModpackResult, -}; -use async_trait::async_trait; -use bytes::Bytes; -use futures::future::try_join_all; -use serde::Deserialize; -use tokio::try_join; - -#[async_trait] -pub trait ModrinthAPI { - async fn get_latest_version( - &self, - project: &str, - channel: &str, - game: &ModpackGame, - ) -> ModpackResult>; - async fn get_version( - &self, - version: &str, - ) -> ModpackResult>; -} - -#[derive(Debug)] -pub struct ModrinthV1(pub String); - -#[derive(Debug, Deserialize)] -struct ModrinthV1Project { - title: String, - client_side: String, - server_side: String, -} - -#[derive(Debug, Deserialize)] -struct ModrinthV1ProjectVersion { - dependencies: HashSet, - game_versions: HashSet, - version_type: String, - files: Vec, - loaders: HashSet, -} - -#[derive(Clone, Debug, Deserialize)] -struct ModrinthV1ProjectVersionFile { - hashes: ManifestHashes, - url: String, - filename: String, -} - -impl From for ModpackFile { - fn from(file: ModrinthV1ProjectVersionFile) -> Self { - Self { - hashes: Some(ModpackFileHashes::from(file.hashes)), - downloads: HashSet::from([file.url]), - path: PathBuf::from(file.filename), - // WARNING: Since the sidedness of version 1 API requests is unknown, the environment is - // set here as both. - env: ModpackEnv::Both, - } - } -} - -#[async_trait] -impl ModrinthAPI for ModrinthV1 { - async fn get_latest_version( - &self, - project: &str, - channel: &str, - game: &ModpackGame, - ) -> ModpackResult> { - let domain = &self.0; - // Fetch metadata - let (project_json, versions_json): (Bytes, Bytes) = try_join!( - try_get_json(format!("{domain}/api/v1/mod/{project}")), - try_get_json(format!("{domain}/api/v1/mod/{project}/version")), - )?; - - let (mut project_deserializer, mut versions_deserializer) = ( - serde_json::Deserializer::from_slice(&project_json), - serde_json::Deserializer::from_slice(&versions_json), - ); - - let (project, versions) = ( - ModrinthV1Project::deserialize(&mut project_deserializer)?, - Vec::deserialize(&mut versions_deserializer)?, - ); - - let (game_version, loader) = match game { - ModpackGame::Minecraft(_, ModLoader::Vanilla) => Err(ModpackError::VersionError( - String::from("Modrinth V1 does not support vanilla projects"), - )), - ModpackGame::Minecraft(ref version, ref loader) => Ok((version, loader)), - // This guard is here for when Modrinth does support other games. - #[allow(unreachable_patterns)] - _ => Err(ModpackError::VersionError(String::from( - "Attempted to use Modrinth API V1 to install a non-Minecraft project!", - ))), - }?; - - let version: ModrinthV1ProjectVersion = versions - .into_iter() - .find(|it: &ModrinthV1ProjectVersion| { - let loader_str = match loader { - ModLoader::Fabric => "fabric", - ModLoader::Forge => "forge", - ModLoader::Vanilla => unreachable!(), - }; - it.version_type == channel - && it.game_versions.contains(game_version) - && it.loaders.contains(loader_str) - }) - .ok_or_else(|| { - ModpackError::VersionError(format!( - "Unable to find compatible version of mod {}", - project.title - )) - })?; - - // Project fields - let envs = ModpackEnv::try_from(ManifestEnvs { - client: serde_json::from_str(&project.client_side)?, - server: serde_json::from_str(&project.server_side)?, - })?; - - // Conversions - let files = version - .files - .iter() - .cloned() - .map(ModpackFile::from) - .collect::>(); - - let dep_futures = - version.dependencies.iter().map(|it| self.get_version(it)); - let deps = try_join_all(dep_futures) - .await? - .into_iter() - .flatten() - .collect::>(); - - Ok(files - .into_iter() - .chain(deps.into_iter()) - .map(|mut it| { - it.env = envs; - it - }) - .collect()) - } - - async fn get_version( - &self, - version: &str, - ) -> ModpackResult> { - let domain = &self.0; - let version_json = - try_get_json(format!("{domain}/api/v1/version/{version}")).await?; - let mut version_deserializer = - serde_json::Deserializer::from_slice(&version_json); - let version = - ModrinthV1ProjectVersion::deserialize(&mut version_deserializer)?; - - Ok(version - .files - .into_iter() - .map(ModpackFile::from) - .collect::>()) - } -} - -// Helpers -async fn try_get_json(url: String) -> ModpackResult { - Ok(reqwest::get(url).await?.error_for_status()?.bytes().await?) -} diff --git a/theseus/src/modpack/pack.rs b/theseus/src/modpack/pack.rs deleted file mode 100644 index 2209f9a3..00000000 --- a/theseus/src/modpack/pack.rs +++ /dev/null @@ -1,277 +0,0 @@ -use daedalus::download_file_mirrors; -use futures::future; -use serde::{Deserialize, Serialize}; -use std::{ - collections::HashSet, - hash::Hash, - iter::FromIterator, - path::{Path, PathBuf}, -}; -use tokio::fs; - -use super::{ - modrinth_api::{self, ModrinthV1}, - ModpackError, ModpackResult, -}; -use crate::launcher::ModLoader; - -pub const MODRINTH_DEFAULT_MODPACK_DOMAINS: &[&str] = &[ - "cdn.modrinth.com", - "edge.forgecdn.net", - "github.com", - "raw.githubusercontent.com", -]; -pub const MODRINTH_MODPACK_DOMAIN_WHITELIST_VAR: &str = "WHITELISTED_MODPACK_DOMAINS"; - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -pub struct Modpack { - pub game: ModpackGame, - pub version: String, - pub name: String, - pub summary: Option, - pub files: HashSet, -} - -impl Modpack { - pub fn new(game: ModpackGame, version: &str, name: &str, summary: Option<&str>) -> Self { - Self { - game, - version: String::from(version), - name: String::from(name), - summary: summary.map(String::from), - files: HashSet::new(), - } - } - - /// Download a modpack's files for a given side to a given destination - /// Assumes the destination exists and is a directory - pub async fn download_files(&self, dest: &Path, side: ModpackSide) -> ModpackResult<()> { - let handles = self.files.iter().cloned().map(move |file| { - let (dest, side) = (dest.to_owned(), side); - tokio::spawn(async move { file.fetch(&dest, side).await }) - }); - future::try_join_all(handles) - .await? - .into_iter() - .collect::>()?; - - // TODO Integrate instance format to save other metadata - Ok(()) - } - - pub async fn add_project( - &mut self, - project: &str, - base_path: &Path, - source: Option<&dyn modrinth_api::ModrinthAPI>, - channel: Option<&str>, - ) -> ModpackResult<()> { - let default_api = ModrinthV1(String::from("https://api.modrinth.com")); - let channel = channel.unwrap_or("release"); - let source = source.unwrap_or(&default_api); - - let files = source - .get_latest_version(project, channel, &self.game) - .await? - .into_iter() - .map(|mut it: ModpackFile| { - it.path = base_path.join(it.path); - it - }); - - self.files.extend(files); - Ok(()) - } - - pub async fn add_version( - &mut self, - version: &str, - base_path: &Path, - source: Option<&dyn modrinth_api::ModrinthAPI>, - ) -> ModpackResult<()> { - let default_api = ModrinthV1(String::from("https://api.modrinth.com")); - let source = source.unwrap_or(&default_api); - - let files = source - .get_version(version) - .await? - .into_iter() - .map(|mut it: ModpackFile| { - it.path = base_path.join(it.path); - it - }); - - self.files.extend(files); - Ok(()) - } - - pub async fn add_file( - &mut self, - source: reqwest::Url, - dest: &Path, - hashes: Option, - env: Option, - ) -> ModpackResult<()> { - let whitelisted_domains = std::env::var(MODRINTH_MODPACK_DOMAIN_WHITELIST_VAR) - .map(|it| serde_json::from_str::>(&it).ok().unwrap()) - .unwrap_or_else(|_| { - MODRINTH_DEFAULT_MODPACK_DOMAINS - .iter() - .cloned() - .map(String::from) - .collect::>() - }); - - if !whitelisted_domains - .iter() - .any(|it| it == source.host_str().unwrap()) - { - return Err(ModpackError::SourceWhitelistError(String::from( - source.host_str().unwrap(), - ))); - } - - let file = ModpackFile { - path: PathBuf::from(dest), - hashes, - env: env.unwrap_or(ModpackEnv::Both), - downloads: HashSet::from_iter([String::from(source)].iter().cloned()), - }; - - self.files.insert(file); - Ok(()) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -#[non_exhaustive] -pub enum ModpackGame { - // TODO: Currently, the launcher does not support specifying mod loader versions, so I just - // store the loader here. - Minecraft(String, ModLoader), -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -pub struct ModpackFile { - pub path: PathBuf, - pub hashes: Option, - pub env: ModpackEnv, - pub downloads: HashSet, -} - -#[allow(clippy::derive_hash_xor_eq)] -impl Hash for ModpackFile { - fn hash(&self, state: &mut H) { - if let Some(ref hashes) = self.hashes { - hashes.sha1.hash(state); - } - self.path.hash(state); - } -} - -impl ModpackFile { - pub async fn fetch(&self, dest: &Path, side: ModpackSide) -> ModpackResult<()> { - if !self.env.supports(side) { - return Ok(()); - } - - let output = dest.join(&self.path); - - // HACK: Since Daedalus appends a file name to all mirrors and the manifest supplies full - // URLs, I'm supplying it with an empty string to avoid reinventing the wheel. - let bytes = download_file_mirrors( - "", - self.downloads - .iter() - .map(|it| it.as_str()) - .collect::>() - .as_slice(), - self.hashes.as_ref().map(|it| it.sha1.as_str()), - ) - .await?; - fs::create_dir_all(output.parent().unwrap()).await?; - fs::write(output, bytes).await?; - Ok(()) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub enum ModpackEnv { - ClientOnly, - ServerOnly, - Both, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ModpackSide { - Client, - Server, -} - -impl ModpackEnv { - pub fn supports(&self, side: ModpackSide) -> bool { - match self { - Self::ClientOnly => side == ModpackSide::Client, - Self::ServerOnly => side == ModpackSide::Server, - Self::Both => true, - } - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -pub struct ModpackFileHashes { - pub sha1: String, -} - -#[cfg(test)] -mod tests { - use std::{ - collections::HashSet, - path::{Path, PathBuf}, - }; - - use super::*; - use crate::launcher::ModLoader; - - #[tokio::test] - async fn add_version() -> ModpackResult<()> { - const TEST_VERSION: &'static str = "TpnSObJ7"; - let mut test_pack = Modpack::new( - ModpackGame::Minecraft(String::from("1.16.5"), ModLoader::Fabric), - "0.1.0", - "Example Modpack", - None, - ); - test_pack - .add_version(TEST_VERSION, Path::new("mods/"), None) - .await?; - - assert_eq!( - test_pack, - Modpack { - game: ModpackGame::Minecraft(String::from("1.16.5"), ModLoader::Fabric), - version: String::from("0.1.0"), - name: String::from("Example Modpack"), - summary: None, - files: { - let mut files = HashSet::new(); - files.insert(ModpackFile { - path: PathBuf::from("mods/gravestones-v1.9.jar"), - hashes: Some(ModpackFileHashes { - sha1: String::from("3f0f6d523d218460310b345be03ab3f1d294e04d"), - }), - env: ModpackEnv::Both, - downloads: { - let mut downloads = HashSet::new(); - downloads.insert(String::from("https://cdn.modrinth.com/data/ssUbhMkL/versions/v1.9/gravestones-v1.9.jar")); - downloads - } - }); - files - }, - }, - ); - Ok(()) - } -} diff --git a/theseus/src/state/dirs.rs b/theseus/src/state/dirs.rs new file mode 100644 index 00000000..3ba115cf --- /dev/null +++ b/theseus/src/state/dirs.rs @@ -0,0 +1,129 @@ +//! Theseus directory information +use std::path::PathBuf; +use tokio::fs; + +#[derive(Debug)] +pub struct DirectoryInfo { + pub config_dir: PathBuf, + pub working_dir: PathBuf, +} + +impl DirectoryInfo { + /// Get all paths needed for Theseus to operate properly + pub async fn init() -> crate::Result { + // Working directory + let working_dir = std::env::current_dir().map_err(|err| { + crate::Error::FSError(format!( + "Could not open working directory: {err}" + )) + })?; + + // Config directory + let config_dir = Self::env_path("THESEUS_CONFIG_DIR") + .or_else(|| Some(dirs::config_dir()?.join("theseus"))) + .ok_or(crate::Error::FSError( + "Could not find valid config dir".to_string(), + ))?; + + fs::create_dir_all(&config_dir).await.map_err(|err| { + crate::Error::FSError(format!( + "Error creating Theseus config directory: {err}" + )) + })?; + + Ok(Self { + config_dir, + working_dir, + }) + } + + /// Get the Minecraft instance metadata directory + #[inline] + pub fn metadata_dir(&self) -> PathBuf { + self.config_dir.join("meta") + } + + /// Get the Minecraft versions metadata directory + #[inline] + pub fn versions_dir(&self) -> PathBuf { + self.metadata_dir().join("versions") + } + + /// Get the metadata directory for a given version + #[inline] + pub fn version_dir(&self, version: &str) -> PathBuf { + self.versions_dir().join(version) + } + + /// Get the Minecraft libraries metadata directory + #[inline] + pub fn libraries_dir(&self) -> PathBuf { + self.metadata_dir().join("libraries") + } + + /// Get the Minecraft assets metadata directory + #[inline] + pub fn assets_dir(&self) -> PathBuf { + self.metadata_dir().join("assets") + } + + /// Get the assets index directory + #[inline] + pub fn assets_index_dir(&self) -> PathBuf { + self.assets_dir().join("indexes") + } + + /// Get the assets objects directory + #[inline] + pub fn objects_dir(&self) -> PathBuf { + self.assets_dir().join("objects") + } + + /// Get the directory for a specific object + #[inline] + pub fn object_dir(&self, hash: &str) -> PathBuf { + self.objects_dir().join(&hash[..2]).join(hash) + } + + /// Get the Minecraft legacy assets metadata directory + #[inline] + pub fn legacy_assets_dir(&self) -> PathBuf { + self.metadata_dir().join("resources") + } + + /// Get the Minecraft legacy assets metadata directory + #[inline] + pub fn natives_dir(&self) -> PathBuf { + self.metadata_dir().join("natives") + } + + /// Get the natives directory for a version of Minecraft + #[inline] + pub fn version_natives_dir(&self, version: &str) -> PathBuf { + self.natives_dir().join(version) + } + + /// Get the directory containing instance icons + #[inline] + pub fn icon_dir(&self) -> PathBuf { + self.config_dir.join("icons") + } + + /// Get the file containing the global database + #[inline] + pub fn database_file(&self) -> PathBuf { + self.config_dir.join("data.bin") + } + + /// Get the settings file for Theseus + #[inline] + pub fn settings_file(&self) -> PathBuf { + self.config_dir.join("settings.json") + } + + /// Get path from environment variable + #[inline] + fn env_path(name: &str) -> Option { + std::env::var_os(name).map(PathBuf::from) + } +} diff --git a/theseus/src/state/metadata.rs b/theseus/src/state/metadata.rs new file mode 100644 index 00000000..eacf59de --- /dev/null +++ b/theseus/src/state/metadata.rs @@ -0,0 +1,90 @@ +//! Theseus metadata +use crate::config::BINCODE_CONFIG; +use bincode::{Decode, Encode}; +use daedalus::{ + minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest}, + modded::{ + fetch_manifest as fetch_loader_manifest, Manifest as LoaderManifest, + }, +}; +use futures::prelude::*; +use std::collections::LinkedList; + +const METADATA_URL: &str = "https://meta.modrinth.com/gamedata"; +const METADATA_DB_FIELD: &[u8] = b"metadata"; + +#[derive(Encode, Decode, Debug)] +pub struct Metadata { + pub minecraft: MinecraftManifest, + pub forge: LoaderManifest, + pub fabric: LoaderManifest, +} + +impl Metadata { + fn get_manifest(name: &str) -> String { + format!("{METADATA_URL}/{name}/v0/manifest.json") + } + + async fn fetch() -> crate::Result { + let (minecraft, forge, fabric) = tokio::try_join! { + async { + let url = Self::get_manifest("minecraft"); + fetch_version_manifest(Some(&url)).await + }, + async { + let url = Self::get_manifest("forge"); + fetch_loader_manifest(&url).await + }, + async { + let url = Self::get_manifest("fabric"); + fetch_loader_manifest(&url).await + } + }?; + + Ok(Self { + minecraft, + forge, + fabric, + }) + } + + pub async fn init(db: &sled::Db) -> crate::Result { + let mut metadata = None; + + if let Some(ref meta_bin) = db.get(METADATA_DB_FIELD)? { + match bincode::decode_from_slice::( + &meta_bin, + *BINCODE_CONFIG, + ) { + Ok((meta, _)) => metadata = Some(meta), + Err(err) => { + log::warn!("Could not read launcher metadata: {err}") + } + } + } + + let mut fetch_futures = LinkedList::new(); + for _ in 0..3 { + fetch_futures.push_back(Self::fetch().boxed()); + } + + match future::select_ok(fetch_futures).await { + Ok(meta) => metadata = Some(meta.0), + Err(err) => log::warn!("Unable to fetch launcher metadata: {err}"), + } + + if let Some(meta) = metadata { + db.insert( + METADATA_DB_FIELD, + sled::IVec::from(bincode::encode_to_vec( + &meta, + *BINCODE_CONFIG, + )?), + )?; + db.flush_async().await?; + Ok(meta) + } else { + Err(crate::Error::NoValueFor(String::from("launcher metadata"))) + } + } +} diff --git a/theseus/src/state/mod.rs b/theseus/src/state/mod.rs new file mode 100644 index 00000000..645c8708 --- /dev/null +++ b/theseus/src/state/mod.rs @@ -0,0 +1,118 @@ +//! Theseus state management system +use crate::config::sled_config; +use std::sync::Arc; +use tokio::sync::{Mutex, OnceCell, RwLock, Semaphore}; + +// Submodules +mod dirs; +pub use self::dirs::*; + +mod metadata; +pub use metadata::*; + +mod settings; +pub use settings::*; + +mod profiles; +pub use profiles::*; + +// Global state +static LAUNCHER_STATE: OnceCell> = OnceCell::const_new(); +#[derive(Debug)] +pub struct State { + /// Database, used to store some information + pub(self) database: sled::Db, + /// Information on the location of files used in the launcher + pub directories: DirectoryInfo, + /// Semaphore used to limit concurrent I/O and avoid errors + pub io_semaphore: Semaphore, + /// Launcher metadata + pub metadata: Metadata, + /// Launcher configuration + pub settings: RwLock, + /// Launcher profile metadata + pub profiles: RwLock, +} + +impl State { + /// Get the current launcher state, initializing it if needed + pub async fn get() -> crate::Result> { + LAUNCHER_STATE + .get_or_try_init(|| async { + // Directories + let directories = DirectoryInfo::init().await?; + + // Database + // TODO: make database versioned + let database = + sled_config().path(directories.database_file()).open()?; + + // Settings + let settings = + Settings::init(&directories.settings_file()).await?; + + // Metadata + let metadata = Metadata::init(&database).await?; + + // Profiles + let profiles = Profiles::init(&database).await?; + + // Loose initializations + let io_semaphore = + Semaphore::new(settings.max_concurrent_downloads); + + Ok(Arc::new(Self { + database, + directories, + io_semaphore, + metadata, + settings: RwLock::new(settings), + profiles: RwLock::new(profiles), + })) + }) + .await + .map(Arc::clone) + } + + /// Synchronize in-memory state with persistent state + pub async fn sync() -> crate::Result<()> { + let state = Self::get().await?; + let batch = Arc::new(Mutex::new(sled::Batch::default())); + + let sync_settings = async { + let state = Arc::clone(&state); + + tokio::spawn(async move { + let reader = state.settings.read().await; + reader.sync(&state.directories.settings_file()).await?; + Ok::<_, crate::Error>(()) + }) + .await + .unwrap() + }; + + let sync_profiles = async { + let state = Arc::clone(&state); + let batch = Arc::clone(&batch); + + tokio::spawn(async move { + let profiles = state.profiles.read().await; + let mut batch = batch.lock().await; + + profiles.sync(&mut batch).await?; + Ok::<_, crate::Error>(()) + }) + .await + .unwrap() + }; + + tokio::try_join!(sync_settings, sync_profiles)?; + + state + .database + .apply_batch(Arc::try_unwrap(batch).unwrap().into_inner())?; + state.database.flush_async().await?; + + Ok(()) + } +} diff --git a/theseus/src/state/profiles.rs b/theseus/src/state/profiles.rs new file mode 100644 index 00000000..5b10b8d2 --- /dev/null +++ b/theseus/src/state/profiles.rs @@ -0,0 +1,340 @@ +use super::settings::{Hooks, MemorySettings, WindowSize}; +use crate::config::BINCODE_CONFIG; +use daedalus::modded::LoaderVersion; +use futures::prelude::*; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; +use tokio::fs; + +const PROFILE_JSON_PATH: &str = "profile.json"; +const PROFILE_SUBTREE: &[u8] = b"profiles"; + +#[derive(Debug)] +pub struct Profiles(pub HashMap>); + +// TODO: possibly add defaults to some of these values +pub const CURRENT_FORMAT_VERSION: u32 = 1; +pub const SUPPORTED_ICON_FORMATS: &[&'static str] = &[ + "bmp", "gif", "jpeg", "jpg", "jpe", "png", "svg", "svgz", "webp", "rgb", + "mp4", +]; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Profile { + #[serde(skip)] + pub path: PathBuf, + pub metadata: ProfileMetadata, + #[serde(skip_serializing_if = "Option::is_none")] + pub java: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub memory: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub resolution: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub hooks: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ProfileMetadata { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub icon: Option, + pub game_version: String, + #[serde(default)] + pub loader: ModLoader, + #[serde(skip_serializing_if = "Option::is_none")] + pub loader_version: Option, + pub format_version: u32, +} + +// TODO: Quilt? +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum ModLoader { + Vanilla, + Forge, + Fabric, +} + +impl Default for ModLoader { + fn default() -> Self { + ModLoader::Vanilla + } +} + +impl std::fmt::Display for ModLoader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + &Self::Vanilla => "Vanilla", + &Self::Forge => "Forge", + &Self::Fabric => "Fabric", + }) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct JavaSettings { + #[serde(skip_serializing_if = "Option::is_none")] + pub install: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub extra_arguments: Option>, +} + +impl Profile { + pub async fn new( + name: String, + version: String, + path: PathBuf, + ) -> crate::Result { + if name.trim().is_empty() { + return Err(crate::Error::InputError(String::from( + "Empty name for instance!", + ))); + } + + Ok(Self { + path: path.canonicalize()?, + metadata: ProfileMetadata { + name, + icon: None, + game_version: version, + loader: ModLoader::Vanilla, + loader_version: None, + format_version: CURRENT_FORMAT_VERSION, + }, + java: None, + memory: None, + resolution: None, + hooks: None, + }) + } + + // TODO: deduplicate these builder methods + // They are flat like this in order to allow builder-style usage + pub fn with_name(&mut self, name: String) -> &mut Self { + self.metadata.name = name; + self + } + + pub async fn with_icon<'a>( + &'a mut self, + icon: &'a Path, + ) -> crate::Result<&'a mut Self> { + let ext = icon + .extension() + .and_then(std::ffi::OsStr::to_str) + .unwrap_or(""); + + if SUPPORTED_ICON_FORMATS.contains(&ext) { + let file_name = format!("icon.{ext}"); + fs::copy(icon, &self.path.join(&file_name)).await?; + self.metadata.icon = + Some(Path::new(&format!("./{file_name}")).to_owned()); + + Ok(self) + } else { + Err(crate::Error::InputError(format!( + "Unsupported image type: {ext}" + ))) + } + } + + pub fn with_game_version(&mut self, version: String) -> &mut Self { + self.metadata.game_version = version; + self + } + + pub fn with_loader( + &mut self, + loader: ModLoader, + version: Option, + ) -> &mut Self { + self.metadata.loader = loader; + self.metadata.loader_version = version; + self + } + + pub fn with_java_settings( + &mut self, + settings: Option, + ) -> &mut Self { + self.java = settings; + self + } + + pub fn with_memory( + &mut self, + settings: Option, + ) -> &mut Self { + self.memory = settings; + self + } + + pub fn with_resolution( + &mut self, + resolution: Option, + ) -> &mut Self { + self.resolution = resolution; + self + } + + pub fn with_hooks(&mut self, hooks: Option) -> &mut Self { + self.hooks = hooks; + self + } +} + +impl Profiles { + pub async fn init(db: &sled::Db) -> crate::Result { + let profile_db = db.get(PROFILE_SUBTREE)?.map_or( + Ok(Default::default()), + |bytes| { + bincode::decode_from_slice::, _>( + &bytes, + *BINCODE_CONFIG, + ) + .map(|it| it.0) + }, + )?; + + let profiles = stream::iter(profile_db.iter()) + .then(|it| async move { + let path = PathBuf::from(it); + let prof = match Self::read_profile_from_dir(&path).await { + Ok(prof) => Some(prof), + Err(err) => { + log::warn!("Error loading profile: {err}. Skipping..."); + None + } + }; + (path, prof) + }) + .collect::>>() + .await; + + Ok(Self(profiles)) + } + + pub fn insert(&mut self, profile: Profile) -> crate::Result<&Self> { + self.0.insert( + profile + .path + .canonicalize()? + .to_str() + .ok_or(crate::Error::UTFError(profile.path.clone()))? + .into(), + Some(profile), + ); + Ok(self) + } + + pub async fn insert_from<'a>( + &'a mut self, + path: &'a Path, + ) -> crate::Result<&Self> { + self.insert(Self::read_profile_from_dir(&path.canonicalize()?).await?) + } + + pub fn remove(&mut self, path: &Path) -> crate::Result<&Self> { + let path = PathBuf::from(path.canonicalize()?.to_str().unwrap()); + self.0.remove(&path); + Ok(self) + } + + pub async fn sync<'a>( + &'a self, + batch: &'a mut sled::Batch, + ) -> crate::Result<&Self> { + stream::iter(self.0.iter()) + .map(Ok::<_, crate::Error>) + .try_for_each_concurrent(None, |(path, profile)| async move { + let json = serde_json::to_vec_pretty(&profile)?; + + let json_path = + Path::new(path.to_str().unwrap()).join(PROFILE_JSON_PATH); + + fs::write(json_path, json).await?; + Ok::<_, crate::Error>(()) + }) + .await?; + + batch.insert( + PROFILE_SUBTREE, + bincode::encode_to_vec( + self.0.keys().collect::>(), + *BINCODE_CONFIG, + )?, + ); + Ok(self) + } + + async fn read_profile_from_dir(path: &Path) -> crate::Result { + let json = fs::read(path.join(PROFILE_JSON_PATH)).await?; + let mut profile = serde_json::from_slice::(&json)?; + profile.path = PathBuf::from(path); + Ok(profile) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::{assert_eq, assert_str_eq}; + use std::collections::HashSet; + + #[test] + fn profile_test() -> Result<(), serde_json::Error> { + let profile = Profile { + path: PathBuf::new(), + metadata: ProfileMetadata { + name: String::from("Example Pack"), + icon: None, + game_version: String::from("1.18.2"), + loader: ModLoader::Vanilla, + loader_version: None, + format_version: CURRENT_FORMAT_VERSION, + }, + java: Some(JavaSettings { + install: Some(PathBuf::from("/usr/bin/java")), + extra_arguments: Some(Vec::new()), + }), + memory: Some(MemorySettings { + minimum: None, + maximum: 8192, + }), + resolution: Some(WindowSize(1920, 1080)), + hooks: Some(Hooks { + pre_launch: HashSet::new(), + wrapper: None, + post_exit: HashSet::new(), + }), + }; + let json = serde_json::json!({ + "metadata": { + "name": "Example Pack", + "game_version": "1.18.2", + "format_version": 1u32, + "loader": "vanilla", + }, + "java": { + "extra_arguments": [], + "install": "/usr/bin/java", + }, + "memory": { + "maximum": 8192u32, + }, + "resolution": (1920u16, 1080u16), + "hooks": {}, + }); + + assert_eq!(serde_json::to_value(profile.clone())?, json.clone()); + assert_str_eq!( + format!("{:?}", serde_json::from_value::(json)?), + format!("{:?}", profile), + ); + Ok(()) + } +} diff --git a/theseus/src/state/settings.rs b/theseus/src/state/settings.rs new file mode 100644 index 00000000..863a3b9a --- /dev/null +++ b/theseus/src/state/settings.rs @@ -0,0 +1,119 @@ +//! Theseus settings file +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashSet, + path::{Path, PathBuf}, +}; +use tokio::fs; + +// TODO: convert to semver? +const CURRENT_FORMAT_VERSION: u32 = 1; + +// Types +/// Global Theseus settings +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(default)] +pub struct Settings { + pub memory: MemorySettings, + pub game_resolution: WindowSize, + pub custom_java_args: Vec, + pub java_8_path: Option, + pub java_17_path: Option, + pub hooks: Hooks, + pub max_concurrent_downloads: usize, + pub version: u32, +} + +impl Default for Settings { + fn default() -> Self { + Self { + memory: MemorySettings::default(), + game_resolution: WindowSize::default(), + custom_java_args: Vec::new(), + java_8_path: None, + java_17_path: None, + hooks: Hooks::default(), + max_concurrent_downloads: 64, + version: CURRENT_FORMAT_VERSION, + } + } +} + +impl Settings { + pub async fn init(file: &Path) -> crate::Result { + if file.exists() { + fs::read(&file) + .await + .map_err(|err| { + crate::Error::FSError(format!( + "Error reading settings file: {err}" + )) + }) + .and_then(|it| { + serde_json::from_slice::(&it) + .map_err(crate::Error::from) + }) + } else { + Ok(Settings::default()) + } + } + + pub async fn sync(&self, to: &Path) -> crate::Result<()> { + fs::write(to, serde_json::to_vec_pretty(self)?) + .await + .map_err(|err| { + crate::Error::FSError(format!( + "Error saving settings to file: {err}" + )) + }) + } +} + +/// Minecraft memory settings +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub struct MemorySettings { + #[serde(skip_serializing_if = "Option::is_none")] + pub minimum: Option, + pub maximum: u32, +} + +impl Default for MemorySettings { + fn default() -> Self { + Self { + minimum: None, + maximum: 2048, + } + } +} + +/// Game window size +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub struct WindowSize(pub u16, pub u16); + +impl Default for WindowSize { + fn default() -> Self { + Self(854, 480) + } +} + +/// Game initialization hooks +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(default)] +pub struct Hooks { + #[serde(skip_serializing_if = "HashSet::is_empty")] + pub pre_launch: HashSet, + #[serde(skip_serializing_if = "Option::is_none")] + pub wrapper: Option, + #[serde(skip_serializing_if = "HashSet::is_empty")] + pub post_exit: HashSet, +} + +impl Default for Hooks { + fn default() -> Self { + Self { + pre_launch: HashSet::::new(), + wrapper: None, + post_exit: HashSet::::new(), + } + } +} diff --git a/theseus/src/util.rs b/theseus/src/util.rs deleted file mode 100644 index 62633378..00000000 --- a/theseus/src/util.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::path::{Path, PathBuf}; -use std::{env, io}; - -use path_clean::PathClean; - -// https://stackoverflow.com/a/54817755 -pub fn absolute_path(path: impl AsRef) -> io::Result { - let path = path.as_ref(); - - let absolute_path = if path.is_absolute() { - path.to_path_buf() - } else { - env::current_dir()?.join(path) - } - .clean(); - - Ok(absolute_path) -} diff --git a/theseus/src/util/fetch.rs b/theseus/src/util/fetch.rs new file mode 100644 index 00000000..fce3ce6c --- /dev/null +++ b/theseus/src/util/fetch.rs @@ -0,0 +1,92 @@ +//! Functions for fetching infromation from the Internet +use crate::config::REQWEST_CLIENT; +use futures::prelude::*; +use std::{collections::LinkedList, convert::TryInto, path::Path, sync::Arc}; +use tokio::{ + fs::{self, File}, + io::AsyncWriteExt, + sync::{Semaphore, SemaphorePermit}, +}; + +const FETCH_ATTEMPTS: usize = 3; + +pub async fn fetch<'a>( + url: &str, + sha1: Option<&str>, + _permit: &SemaphorePermit<'a>, +) -> crate::Result { + let mut attempts = LinkedList::new(); + for _ in 0..FETCH_ATTEMPTS { + attempts.push_back( + async { + let content = REQWEST_CLIENT.get(url).send().await?; + let bytes = content.bytes().await?; + + if let Some(hash) = sha1 { + let actual_hash = sha1_async(bytes.clone()).await; + if actual_hash != hash { + return Err(crate::Error::HashError( + actual_hash, + String::from(hash), + )); + } + } + + Ok(bytes) + } + .boxed(), + ) + } + + log::debug!("Done downloading URL {url}"); + future::select_ok(attempts).map_ok(|it| it.0).await +} + +// This is implemented, as it will be useful in porting modpacks +// For now, allow it to be dead code +#[allow(dead_code)] +pub async fn fetch_mirrors( + urls: &[&str], + sha1: Option<&str>, + permits: u32, + sem: &Semaphore, +) -> crate::Result { + let _permits = sem.acquire_many(permits).await.unwrap(); + let sem = Arc::new(Semaphore::new(permits.try_into().unwrap())); + + future::select_ok(urls.into_iter().map(|url| { + let sha1 = sha1.map(String::from); + let url = String::from(*url); + let sem = Arc::clone(&sem); + + tokio::spawn(async move { + let permit = sem.acquire().await.unwrap(); + fetch(&url, sha1.as_deref(), &permit).await + }) + .map(Result::unwrap) + .boxed() + })) + .await + .map(|it| it.0) +} + +pub async fn write<'a>( + path: &Path, + bytes: &[u8], + _permit: &SemaphorePermit<'a>, +) -> crate::Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent).await?; + } + + let mut file = File::create(path).await?; + log::debug!("Done writing file {}", path.display()); + file.write_all(bytes).await?; + Ok(()) +} + +async fn sha1_async(bytes: bytes::Bytes) -> String { + tokio::task::spawn_blocking(move || sha1::Sha1::from(bytes).hexdigest()) + .await + .unwrap() +} diff --git a/theseus/src/util/mod.rs b/theseus/src/util/mod.rs new file mode 100644 index 00000000..c664986d --- /dev/null +++ b/theseus/src/util/mod.rs @@ -0,0 +1,3 @@ +//! Theseus utility functions +pub mod fetch; +pub mod platform; diff --git a/theseus/src/util/platform.rs b/theseus/src/util/platform.rs new file mode 100644 index 00000000..b403d884 --- /dev/null +++ b/theseus/src/util/platform.rs @@ -0,0 +1,60 @@ +//! Platform-related code +use daedalus::minecraft::{Os, OsRule}; +use regex::Regex; + +// OS detection +pub trait OsExt { + /// Get the OS of the current system + fn native() -> Self; +} + +impl OsExt for Os { + fn native() -> Self { + match std::env::consts::OS { + "windows" => Self::Windows, + "macos" => Self::Osx, + "linux" => Self::Linux, + _ => Self::Unknown, + } + } +} + +// Bit width +#[cfg(target_pointer_width = "64")] +pub const ARCH_WIDTH: &str = "64"; + +#[cfg(target_pointer_width = "32")] +pub const ARCH_WIDTH: &str = "32"; + +// Platform rule handling +pub fn os_rule(rule: &OsRule) -> bool { + let mut rule_match = true; + + if let Some(ref arch) = rule.arch { + rule_match &= match arch.as_str() { + "x86" => cfg!(any(target_arch = "x86", target_arch = "x86_64")), + "arm" => cfg!(target_arch = "arm"), + _ => true, + }; + } + + if let Some(name) = &rule.name { + rule_match &= &Os::native() == name; + } + + if let Some(version) = &rule.version { + if let Ok(regex) = Regex::new(version.as_str()) { + rule_match &= + regex.is_match(&sys_info::os_release().unwrap_or_default()); + } + } + + rule_match +} + +pub fn classpath_separator() -> &'static str { + match Os::native() { + Os::Osx | Os::Linux | Os::Unknown => ":", + Os::Windows => ";", + } +} diff --git a/theseus_cli/Cargo.toml b/theseus_cli/Cargo.toml index e0ee01db..d51a5721 100644 --- a/theseus_cli/Cargo.toml +++ b/theseus_cli/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] theseus = { path = "../theseus" } -daedalus = "0.1.12" +daedalus = {version = "0.1.15", features = ["bincode"]} tokio = { version = "1", features = ["full"] } tokio-stream = { version = "0.1", features = ["fs"] } futures = "0.3" @@ -18,4 +18,7 @@ dialoguer = "0.10" eyre = "0.6" tabled = "0.5" dirs = "4.0" -uuid = {version = "0.8", features = ["v4", "serde"]} \ No newline at end of file +uuid = {version = "0.8", features = ["v4", "serde"]} +# TODO: merge logging with paris logging +pretty_env_logger = "0.4" +log = "0.4.14" diff --git a/theseus_cli/src/main.rs b/theseus_cli/src/main.rs index 58063180..6b92766d 100644 --- a/theseus_cli/src/main.rs +++ b/theseus_cli/src/main.rs @@ -15,10 +15,12 @@ pub struct Args { #[tokio::main] async fn main() -> Result<()> { let args = argh::from_env::(); - theseus::init().await?; + pretty_env_logger::formatted_builder() + .filter_module("theseus", log::LevelFilter::Info) + .target(pretty_env_logger::env_logger::Target::Stderr) + .init(); args.dispatch() .inspect_err(|_| error!("An error has occurred!\n")) - .and_then(|_| async { Ok(theseus::save().await?) }) .await } diff --git a/theseus_cli/src/subcommands/profile.rs b/theseus_cli/src/subcommands/profile.rs index 3aacbc4b..c39e67be 100644 --- a/theseus_cli/src/subcommands/profile.rs +++ b/theseus_cli/src/subcommands/profile.rs @@ -4,15 +4,13 @@ use crate::util::{ }; use daedalus::modded::LoaderVersion; use eyre::{ensure, Result}; +use futures::prelude::*; use paris::*; use std::path::{Path, PathBuf}; use tabled::{Table, Tabled}; -use theseus::{ - data::{profiles::PROFILE_JSON_PATH, Metadata, Profile, Profiles}, - launcher::ModLoader, -}; +use theseus::prelude::*; use tokio::fs; -use tokio_stream::{wrappers::ReadDirStream, StreamExt}; +use tokio_stream::wrappers::ReadDirStream; use uuid::Uuid; #[derive(argh::FromArgs)] @@ -54,16 +52,19 @@ impl ProfileAdd { ); let profile = self.profile.canonicalize()?; - let json_path = profile.join(PROFILE_JSON_PATH); + let json_path = profile.join("profile.json"); + ensure!( json_path.exists(), "Profile json does not exist. Perhaps you wanted `profile init` or `profile fetch`?" ); ensure!( - Profiles::get().await.unwrap().0.get(&profile).is_none(), + !profile::is_managed(&profile).await?, "Profile already managed by Theseus. If the contents of the profile are invalid or missing, the profile can be regenerated using `profile init` or `profile fetch`" ); - Profiles::insert_from(profile).await?; + + profile::add_path(&profile).await?; + State::sync().await?; success!("Profile added!"); Ok(()) @@ -106,13 +107,15 @@ impl ProfileInit { _largs: &ProfileCommand, ) -> Result<()> { // TODO: validate inputs from args early + let state = State::get().await?; + if self.path.exists() { ensure!( self.path.is_dir(), "Attempted to create profile in something other than a folder!" ); ensure!( - !self.path.join(PROFILE_JSON_PATH).exists(), + !self.path.join("profile.json").exists(), "Profile already exists! Perhaps you want `profile add` instead?" ); if ReadDirStream::new(fs::read_dir(&self.path).await?) @@ -138,8 +141,6 @@ impl ProfileInit { &self.path.canonicalize()?.display() ); - let metadata = Metadata::get().await?; - // TODO: abstract default prompting let name = match &self.name { Some(name) => name.clone(), @@ -157,7 +158,7 @@ impl ProfileInit { let game_version = match &self.game_version { Some(version) => version.clone(), None => { - let default = &metadata.minecraft.latest.release; + let default = &state.metadata.minecraft.latest.release; prompt_async( String::from("Game version"), @@ -206,8 +207,8 @@ impl ProfileInit { }; let loader_data = match loader { - ModLoader::Forge => &metadata.forge, - ModLoader::Fabric => &metadata.fabric, + ModLoader::Forge => &state.metadata.forge, + ModLoader::Fabric => &state.metadata.fabric, _ => eyre::bail!("Could not get manifest for loader {loader}. This is a bug in the CLI!"), }; @@ -238,8 +239,6 @@ impl ProfileInit { .map(PathBuf::from), }; - // We don't really care if the profile already is managed, as getting this far means that the user probably wanted to re-create a profile - drop(metadata); let mut profile = Profile::new(name, game_version, self.path.clone()).await?; @@ -251,8 +250,8 @@ impl ProfileInit { profile.with_loader(loader, Some(loader_version)); } - Profiles::insert(profile).await?; - Profiles::save().await?; + profile::add(profile).await?; + State::sync().await?; success!( "Successfully created instance, it is now available to use with Theseus!" @@ -294,20 +293,39 @@ impl<'a> From<&'a Profile> for ProfileRow<'a> { } } +impl<'a> From<&'a Path> for ProfileRow<'a> { + fn from(it: &'a Path) -> Self { + Self { + name: "?", + path: it, + game_version: "?", + loader: &ModLoader::Vanilla, + loader_version: "?", + } + } +} + impl ProfileList { pub async fn run( &self, _args: &crate::Args, _largs: &ProfileCommand, ) -> Result<()> { - let profiles = Profiles::get().await?; - let profiles = profiles.0.values().map(ProfileRow::from); + let state = State::get().await?; + let profiles = state.profiles.read().await; + let profiles = profiles.0.iter().map(|(path, prof)| { + prof.as_ref().map_or_else( + || ProfileRow::from(path.as_path()), + ProfileRow::from, + ) + }); let table = Table::new(profiles).with(tabled::Style::psql()).with( tabled::Modify::new(tabled::Column(1..=1)) .with(tabled::MaxWidth::wrapping(40)), ); println!("{table}"); + Ok(()) } } @@ -329,10 +347,13 @@ impl ProfileRemove { ) -> Result<()> { let profile = self.profile.canonicalize()?; info!("Removing profile {} from Theseus", self.profile.display()); + if confirm_async(String::from("Do you wish to continue"), true).await? { - if Profiles::remove(&profile).await?.is_none() { + if !profile::is_managed(&profile).await? { warn!("Profile was not managed by Theseus!"); } else { + profile::remove(&profile).await?; + State::sync().await?; success!("Profile removed!"); } } else { @@ -372,24 +393,21 @@ impl ProfileRun { _largs: &ProfileCommand, ) -> Result<()> { info!("Starting profile at path {}...", self.profile.display()); - let ref profiles = Profiles::get().await?.0; let path = self.profile.canonicalize()?; - let profile = profiles - .get(&path) - .ok_or( - eyre::eyre!( - "Profile not managed by Theseus (if it exists, try using `profile add` first!)" - ) - )?; - let credentials = theseus::launcher::Credentials { + ensure!( + profile::is_managed(&path).await?, + "Profile not managed by Theseus (if it exists, try using `profile add` first!)", + ); + + let credentials = Credentials { id: self.id.clone(), username: self.name.clone(), access_token: self.token.clone(), }; - let mut proc = profile.run(&credentials).await?; - profile.wait_for(&mut proc).await?; + let mut proc = profile::run(&path, &credentials).await?; + profile::wait_for(&mut proc).await?; success!("Process exited successfully!"); Ok(())