diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0b30b92b..5af0f76a 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -11,7 +11,6 @@ jobs: outputs: rust: ${{ steps.filter.outputs.rust }} cargo: ${{ steps.filter.outputs.cargo }} - pytests: ${{ steps.filter.outputs.pytests }}} steps: - uses: actions/checkout@v3 - uses: dorny/paths-filter@v2 @@ -39,6 +38,74 @@ jobs: # Push-only API key fossa-api-key: 7b6d2d5fb78bb718019e16184020ef6d + msrv: + name: Cargo MSRV + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: clippy, rustfmt + + - name: Install cargo-msrv + uses: actions-rs/install@v0.1 + with: + crate: cargo-msrv + version: latest + use-tool-cache: true + + - name: Install cargo-make + uses: actions-rs/install@v0.1 + with: + crate: cargo-make + version: latest + use-tool-cache: true + + - name: Cargo msrv + uses: actions-rs/cargo@v1 + with: + command: make + args: msrv-verify + + deny: + name: Cargo deny + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: clippy, rustfmt + + - name: Install cargo-deny + uses: actions-rs/install@v0.1 + with: + crate: cargo-deny + version: latest + use-tool-cache: true + + - name: Install cargo-make + uses: actions-rs/install@v0.1 + with: + crate: cargo-make + version: latest + use-tool-cache: true + + - name: Cargo deny + uses: actions-rs/cargo@v1 + with: + command: make + args: deny + fmt: name: Cargo fmt runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index c34c5a59..9d5bb640 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,40 +3,54 @@ version = 3 [[package]] -name = "aho-corasick" +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] @@ -52,9 +66,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys", @@ -84,9 +98,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", @@ -94,27 +108,37 @@ dependencies = [ ] [[package]] -name = "atty" -version = "0.2.14" +name = "autocfg" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ - "hermit-abi 0.1.19", + "addr2line", + "cc", + "cfg-if", "libc", - "winapi", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "block-buffer" @@ -127,15 +151,18 @@ dependencies = [ [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -145,24 +172,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.3.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", "terminal_size", @@ -170,9 +195,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", @@ -182,9 +207,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "colorchoice" @@ -194,9 +219,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -211,6 +236,28 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] + [[package]] name = "digest" version = "0.10.7" @@ -223,15 +270,21 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" dependencies = [ "errno-dragonfly", "libc", @@ -250,12 +303,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fixedbitset" @@ -370,6 +420,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + [[package]] name = "glob" version = "0.3.1" @@ -378,9 +434,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" [[package]] name = "heck" @@ -390,27 +446,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -424,7 +462,6 @@ version = "0.5.2" dependencies = [ "async-stream", "async-trait", - "atty", "clap", "digest", "futures", @@ -434,7 +471,7 @@ dependencies = [ "itertools", "maplit", "md-5", - "nix 0.26.2", + "nix 0.27.1", "once_cell", "open_cmd", "petgraph", @@ -446,6 +483,7 @@ dependencies = [ "serde_json", "serde_test", "serde_yaml", + "serial_test", "sha2", "similar", "tap", @@ -461,6 +499,15 @@ dependencies = [ "windows", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "hostname" version = "0.3.1" @@ -484,60 +531,28 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys", -] - [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "lazy_static" @@ -547,21 +562,31 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "maplit" @@ -581,23 +606,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -609,12 +635,12 @@ dependencies = [ ] [[package]] -name = "memoffset" +name = "miniz_oxide" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "autocfg", + "adler", ] [[package]] @@ -634,25 +660,22 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset", ] [[package]] name = "nix" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags", + "bitflags 2.4.0", "cfg-if", "libc", - "memoffset 0.7.1", - "pin-utils", - "static_assertions", ] [[package]] @@ -667,14 +690,23 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -700,6 +732,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "path-clean" version = "0.1.0" @@ -714,9 +769,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", "indexmap", @@ -724,9 +779,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -742,9 +797,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -761,9 +816,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -804,18 +859,19 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.8.4" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.9", + "regex-syntax 0.7.5", ] [[package]] @@ -827,6 +883,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -835,9 +902,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "registry" @@ -845,22 +912,27 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3b6d580d46b9d6d6c291f90c5d762e8b93a268a96e429556419fcd7e349f94" dependencies = [ - "bitflags", + "bitflags 1.3.2", "log", "thiserror", "utfx", "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" -version = "0.37.20" +version = "0.38.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", @@ -868,24 +940,30 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -894,9 +972,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -905,27 +983,27 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] [[package]] name = "serde_test" -version = "1.0.164" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797c38160e2546a56e1e3439496439597e938669673ffd8af02a12f070da648f" +checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" dependencies = [ "serde", ] [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ "indexmap", "itoa", @@ -934,11 +1012,36 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -947,9 +1050,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -971,24 +1074,18 @@ checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "strsim" @@ -998,9 +1095,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.18" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -1015,11 +1112,10 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall", @@ -1029,9 +1125,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ "rustix", "windows-sys", @@ -1039,18 +1135,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", @@ -1069,10 +1165,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -1081,15 +1178,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -1111,11 +1208,11 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -1150,9 +1247,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", @@ -1162,18 +1259,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap", "serde", @@ -1196,9 +1293,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", @@ -1233,9 +1330,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" @@ -1245,9 +1342,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1260,15 +1357,15 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -1289,9 +1386,9 @@ checksum = "133bf74f01486773317ddfcde8e2e20d2933cc3b68ab797e5d718bef996a81de" [[package]] name = "uuid" -version = "1.3.4" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom", "serde", @@ -1311,13 +1408,14 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "which" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix", ] [[package]] @@ -1344,9 +1442,19 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.48.0" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets", ] @@ -1362,9 +1470,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1377,51 +1485,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index d5e8581e..39e54067 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ license = "BSD-3-Clause" description = "Hoard backups of files across your filesystem into one location." homepage = "https://github.com/Shadow53/hoard" repository = "https://github.com/Shadow53/hoard" +rust-version = "1.70.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] @@ -16,20 +17,20 @@ yaml = ["serde_yaml"] [dependencies] async-stream = "0.3" async-trait = "0.1" -atty = "0.2" clap = { version = "4.3", features = ["derive", "wrap_help"] } digest = "0.10.7" futures = { version = "0.3", default-features = false, features = [] } glob = "0.3" hex = "0.4.3" hostname = "0.3" -itertools = "0.10" +itertools = "0.11.0" md-5 = "0.10.5" once_cell = "1.15" open_cmd = { version = "0.1.0", features = ["tracing"] } petgraph = "0.6" regex = "1.8" -serde = { version = "1.0", features = ["derive"] } +# Use at least 1.0.184 because of serde-rs/serde#2538 +serde = { version = ">=1.0.184", features = ["derive"] } serde_json = "1.0" serde_yaml = { version = "0.9", optional = true } sha2 = "0.10.7" @@ -40,13 +41,13 @@ thiserror = "1.0.40" time = { version = "0.3", default-features = false, features = ["formatting", "macros", "serde", "std"] } tokio = { version = "1.28", default-features = false, features = ["rt-multi-thread", "fs", "io-util", "macros"] } tokio-stream = { version = "0.1", default-features = false, features = ["fs"] } -toml = "0.7.4" +toml = "0.8.2" tracing = "0.1" tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "fmt", "env-filter", "smallvec", "std"] } uuid = { version = "1.3", features = ["serde", "v4"] } [target.'cfg(windows)'.dependencies] -windows = { version = "0.48", features = ["Storage", "Win32_UI_Shell", "Win32_Foundation", "Win32_Globalization"] } +windows = { version = "0.51", features = ["Storage", "Win32_UI_Shell", "Win32_Foundation", "Win32_Globalization"] } [dev-dependencies] maplit = "1.0" @@ -54,10 +55,11 @@ rand = "0.8" serde_test = "1.0" futures = { version = "0.3", default-features = false, features = ["executor"] } tokio = { version = "1.28", default-features = false, features = ["process"] } +serial_test = "2.0.0" [target.'cfg(windows)'.dev-dependencies] registry = "1.2" [target.'cfg(unix)'.dev-dependencies] -nix = "0.26" +nix = "0.27" pty_closure = "0.1" diff --git a/Makefile.toml b/Makefile.toml index 622a1bad..7dda3212 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -22,6 +22,10 @@ RUSTFLAGS="-Cinstrument-coverage" LLVM_PROFILE_FILE="profraw/hoard-python-test-%p-%m.profraw" +[tasks.deny] + command = "cargo" + args = ["deny", "check"] + [tasks.test-nextest] dependencies = ["clean-all", "install-stable", "create-profraw-dir"] command = "cargo" @@ -49,7 +53,8 @@ """ [tasks.test-all] - dependencies = ["test-nextest", "docker-tests"] + # Do docker tests first so ./target is not sent to Docker + dependencies = ["docker-tests", "test-nextest"] [tasks.grcov] dependencies = ["clean-all", "test-all"] @@ -84,15 +89,23 @@ [tasks.outdated] command = "cargo" - args = ["outdated"] + args = ["outdated", "-R"] [tasks.deadlinks] command = "cargo" args = ["deadlinks"] [tasks.check-all] - dependencies = ["clippy", "check-format", "docs", "test-all", "deadlinks"] + dependencies = ["clippy", "check-format", "docs", "test-nextest", "deadlinks", "deny", "msrv-verify"] [tasks.changelog] command = "git-cliff" args = ["-o", "CHANGELOG.md"] + +[tasks.msrv] + command = "cargo" + args = ["msrv"] + +[tasks.msrv-verify] + command = "cargo" + args = ["msrv", "verify"] diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 7f543c2f..b2208d96 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -18,7 +18,8 @@ - [Checks](./cli/checks.md) - [Configuration File](./config/README.md) - - [Environments](./config/envs.md) + - [Environments](./config/environments.md) + - [Environment Variables](./config/envvars.md) - [Hoards and Piles](./config/hoards-piles.md) - [File Permissions](./permissions.md) diff --git a/book/src/config/environments.md b/book/src/config/environments.md new file mode 100644 index 00000000..01058cdb --- /dev/null +++ b/book/src/config/environments.md @@ -0,0 +1,54 @@ +# Environments + +The path used for a given pile depends on the best matching environment(s) for a configured path. This page +discusses how to define environments. For how to use them with hoards/piles, see +[Hoards and Piles](hoards-piles.md). + +Environments can be matched on one or more of five possible factors: + +- `os`: [Operating System](https://doc.rust-lang.org/stable/std/env/consts/constant.OS.html) +- `env`: Environment variables + - Can match on just existence or also a specific value. +- `hostname`: The system hostname. +- `exe_exists`: Whether an executable file exists in `$PATH`. +- `path_exists`: Whether something exists (one of) the given path(s). + +All the above factors can be written using two-dimensional array syntax. That is, +`["foo", ["bar, "baz"]]` is interpreted as `(foo) OR (bar AND baz)`, in whatever way applies +to that given factor. + +It is an error to include an `AND` condition for `os` or `hostname`, as a system can only have +one of each. + +```toml +[envs] +[envs.example_env] + # Matching something *nix-y + os = ["linux", "freebsd"] + # Either sed and sh, or bash, must exist + exe_exists = ["bash", ["sh", "sed"]] + # Require both $HOME to exist and $HOARD_EXAMPLE_ENV to equal YES. + # Note the double square brackets that indicate AND instead of OR. + env = [[ + { var = "HOME" }, + { var = "HOARD_EXAMPLE_ENV", expected = "YES" }, + ]] +``` + +## Exclusivity + +The exclusivity lists indicate names of environments that are considered mutually exclusive to +each other -- that is, cannot appear in the same environment condition -- and the order indicates +which one(s) have precedence when matching environments. + +See the [example config file][example config] for a more thorough example. + +[example config]: https://github.com/Shadow53/hoard/tree/main/config.toml.sample + +```toml +exclusivity = [ + # Assuming all else the same, an environment condition string with "neovim" will take + # precedence over one with "vim", which takes precedence over one with "emacs". + ["neovim", "vim", "emacs"] +] +``` diff --git a/book/src/config/envs.md b/book/src/config/envs.md index 01058cdb..d27141e9 100644 --- a/book/src/config/envs.md +++ b/book/src/config/envs.md @@ -1,54 +1 @@ # Environments - -The path used for a given pile depends on the best matching environment(s) for a configured path. This page -discusses how to define environments. For how to use them with hoards/piles, see -[Hoards and Piles](hoards-piles.md). - -Environments can be matched on one or more of five possible factors: - -- `os`: [Operating System](https://doc.rust-lang.org/stable/std/env/consts/constant.OS.html) -- `env`: Environment variables - - Can match on just existence or also a specific value. -- `hostname`: The system hostname. -- `exe_exists`: Whether an executable file exists in `$PATH`. -- `path_exists`: Whether something exists (one of) the given path(s). - -All the above factors can be written using two-dimensional array syntax. That is, -`["foo", ["bar, "baz"]]` is interpreted as `(foo) OR (bar AND baz)`, in whatever way applies -to that given factor. - -It is an error to include an `AND` condition for `os` or `hostname`, as a system can only have -one of each. - -```toml -[envs] -[envs.example_env] - # Matching something *nix-y - os = ["linux", "freebsd"] - # Either sed and sh, or bash, must exist - exe_exists = ["bash", ["sh", "sed"]] - # Require both $HOME to exist and $HOARD_EXAMPLE_ENV to equal YES. - # Note the double square brackets that indicate AND instead of OR. - env = [[ - { var = "HOME" }, - { var = "HOARD_EXAMPLE_ENV", expected = "YES" }, - ]] -``` - -## Exclusivity - -The exclusivity lists indicate names of environments that are considered mutually exclusive to -each other -- that is, cannot appear in the same environment condition -- and the order indicates -which one(s) have precedence when matching environments. - -See the [example config file][example config] for a more thorough example. - -[example config]: https://github.com/Shadow53/hoard/tree/main/config.toml.sample - -```toml -exclusivity = [ - # Assuming all else the same, an environment condition string with "neovim" will take - # precedence over one with "vim", which takes precedence over one with "emacs". - ["neovim", "vim", "emacs"] -] -``` diff --git a/book/src/config/envvars.md b/book/src/config/envvars.md new file mode 100644 index 00000000..3778f87b --- /dev/null +++ b/book/src/config/envvars.md @@ -0,0 +1,40 @@ +# Environment Variables + +## Default Values + +You may define default values for environment variables, should they not be set when `hoard` is run. If the variable +*is* set, the default value is ignored. Default values may include [interpolated](#interpolation) values of other +environment variables, including other variables with assigned defaults. + +> Make sure there are no cyclical value definitions, as these will cause errors. +> +> ```toml +> [defaults] +> # This will never resolve +> "SELF_CYCLICAL" = "I am ${SELF_CYCLICAL}" +> # These will cause errors if both are undefined, but +> # the errors will not be apparent if one is defined. +> "MUTUALLY_CYCLICAL_1" = "I'm the sibling of ${MUTUTALLY_CYCLICAL_2}" +> "MUTUALLY_CYCLICAL_2" = "I'm the sibling of ${MUTUALLY_CYCLICAL_1}" +> ``` + +### Examples + +This example sets `$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`, two variables that are commonly used on Unix-y systems to +determine where application configuration and data files should be kept. + +```toml +[defaults] + XDG_CONFIG_HOME = "${HOME}/.config" + XDG_DATA_HOME = "${HOME}/.local/share" +``` + +## Interpolation + +Environment variables may be interpolated into certain parts of the configuration file. Namely, + +- [Hoard/Pile paths](./hoards-piles.md#environment-variables) +- [Environment variable default values](#default-values) + +Interpolate a variable using `${VAR}`, where `VAR` is the name of the variable. See the above links for specific +examples. \ No newline at end of file diff --git a/book/src/getting-started/create-config/README.md b/book/src/getting-started/create-config/README.md index 9ca1177e..ebc05b8d 100644 --- a/book/src/getting-started/create-config/README.md +++ b/book/src/getting-started/create-config/README.md @@ -30,10 +30,10 @@ When adding configuration for a specific file or set of files, consider: - What to name the hoard and, optionally, the pile or piles within it. See the examples linked above for ideas of how to structure hoards. - What conditions must be true for a path to be used. These determine the environments, or - [`envs`](../../config/envs.md) that you will define. + [`envs`](../../config/environments.md) that you will define. - If there are multiple, mutually exclusive conditions that can be true at the same time (see [Vim and Neovim](vim-neovim.md) for an example). This determines if you need to add anything under - [`exclusivity`](../../config/envs.md#exclusivity). + [`exclusivity`](../../config/environments.md#exclusivity). - Whether the programs use environment variables to determine where to place files, or if it is hardcoded. This will inform whether you use environment variables in the pile path or not. - Whether there are files in a directory that you want to [ignore](../../config/hoards-piles.md#ignore-patterns) when diff --git a/book/src/getting-started/create-config/games.md b/book/src/getting-started/create-config/games.md index 6e4c80ab..15d8bc80 100644 --- a/book/src/getting-started/create-config/games.md +++ b/book/src/getting-started/create-config/games.md @@ -41,7 +41,7 @@ for the game stores, since all three of them could be installed at once time. > The double square brackets (`[[]]`) are used to indicate that *all* of the XDG environment variables are set. If > single square brackets (`[]`) were used, it would mean that *at least one* must be set. > -> For more, see the documentation for [environments](../../config/envs.md). +> For more, see the documentation for [environments](../../config/environments.md). ```toml exclusivity = [ diff --git a/config.toml.sample b/config.toml.sample index 65c71f44..50ab28ed 100644 --- a/config.toml.sample +++ b/config.toml.sample @@ -9,6 +9,10 @@ exclusivity = [ ["steam_flatpak", "steam"] ] +[defaults] + XDG_CONFIG_HOME = "${HOME}/.config" + XDG_DATA_HOME = "${HOME}/.local/share" + [envs] # Match if `fish` is somewhere in $PATH. diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..d769881c --- /dev/null +++ b/deny.toml @@ -0,0 +1,272 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +# Root options + +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #{ triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] +# When creating the dependency graph used as the source of truth when checks are +# executed, this field can be used to prune crates from the graph, removing them +# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate +# is pruned from the graph, all of its dependencies will also be pruned unless +# they are connected to another crate in the graph that hasn't been pruned, +# so it should be used with care. The identifiers are [Package ID Specifications] +# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) +#exclude = [] +# If true, metadata will be collected with `--all-features`. Note that this can't +# be toggled off if true, if you want to conditionally enable `--all-features` it +# is recommended to pass `--all-features` on the cmd line instead +all-features = true +# If true, metadata will be collected with `--no-default-features`. The same +# caveat with `all-features` applies +no-default-features = false +# If set, these feature will be enabled when collecting metadata. If `--features` +# is specified on the cmd line they will take precedence over this option. +#features = [] +# When outputting inclusion graphs in diagnostics that include features, this +# option can be used to specify the depth at which feature edges will be added. +# This option is included since the graphs can be quite large and the addition +# of features from the crate(s) to all of the graph roots can be far too verbose. +# This option can be overridden via `--feature-depth` on the cmd line +feature-depth = 1 + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url(s) of the advisory databases to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "deny" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. Note that as of +# 2019-12-17 there are no security notice advisories in +# https://github.com/rustsec/advisory-db +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + #"RUSTSEC-0000-0000", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# If this is true, then cargo deny will use the git executable to fetch advisory database. +# If this is false, then it uses a built-in git library. +# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. +# See Git Authentication for more information about setting up git authentication. +#git-fetch-with-cli = true + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# The lint level for crates which do not have a detectable license +unlicensed = "deny" +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +allow = [ + #"MIT", + #"Apache-2.0", + #"Apache-2.0 WITH LLVM-exception", +] +# List of explicitly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +deny = [ + #"Nokia", +] +# Lint level for licenses considered copyleft +copyleft = "deny" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi - The license will be approved if it is OSI approved +# * fsf - The license will be approved if it is FSF Free +# * osi-only - The license will be approved if it is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if it is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "either" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # Each entry is the crate and version constraint, and its specific allow + # list + #{ allow = ["Zlib"], name = "adler32", version = "*" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +#[[licenses.clarify]] +# The name of the crate the clarification applies to +#name = "ring" +# The optional version constraint for the crate +#version = "*" +# The SPDX expression for the license requirements of the crate +#expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +#license-files = [ + # Each entry is a crate relative path, and the (opaque) hash of its contents + #{ path = "LICENSE", hash = 0xbd0eed23 } +#] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries. +# To see how to mark a crate as unpublished (to the official registry), +# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# Lint level for when a crate version requirement is `*` +wildcards = "allow" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# The default lint level for `default` features for crates that are members of +# the workspace that is being checked. This can be overridden by allowing/denying +# `default` on a crate-by-crate basis if desired. +workspace-default-features = "allow" +# The default lint level for `default` features for external crates that are not +# members of the workspace. This can be overridden by allowing/denying `default` +# on a crate-by-crate basis if desired. +external-default-features = "allow" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + #{ name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, + { name = "serde", version = ">=1.0.172,<=1.0.184" }, +] + +# List of features to allow/deny +# Each entry the name of a crate and a version range. If version is +# not specified, all versions will be matched. +#[[bans.features]] +#name = "reqwest" +# Features to not allow +#deny = ["json"] +# Features to allow +#allow = [ +# "rustls", +# "__rustls", +# "__tls", +# "hyper-rustls", +# "rustls", +# "rustls-pemfile", +# "rustls-tls-webpki-roots", +# "tokio-rustls", +# "webpki-roots", +#] +# If true, the allowed features must exactly match the enabled feature set. If +# this is set there is no point setting `deny` +#exact = true + +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite. +skip-tree = [ + #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "deny" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "deny" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] + +[sources.allow-org] +# 1 or more github.com organizations to allow git sources for +github = [] +# 1 or more gitlab.com organizations to allow git sources for +gitlab = [] +# 1 or more bitbucket.org organizations to allow git sources for +bitbucket = [] diff --git a/src/checkers/history/mod.rs b/src/checkers/history/mod.rs index ade9b8d1..a437f12c 100644 --- a/src/checkers/history/mod.rs +++ b/src/checkers/history/mod.rs @@ -82,6 +82,7 @@ async fn get_history_dirs_not_for_id(id: &Uuid) -> Result, io::Er /// /// Any I/O unexpected errors that may occur while reading and/or /// writing the UUID file. +#[allow(clippy::missing_panics_doc)] pub async fn get_or_generate_uuid() -> Result { let uuid_file = get_uuid_file(); let _span = tracing::debug_span!("get_or_generate_uuid", file = ?uuid_file); diff --git a/src/checkers/history/operation/util.rs b/src/checkers/history/operation/util.rs index 3d7abd68..c35af312 100644 --- a/src/checkers/history/operation/util.rs +++ b/src/checkers/history/operation/util.rs @@ -173,6 +173,10 @@ pub(crate) async fn cleanup_operations() -> Result { // Get hoard history root // Iterate over every uuid in the directory let root = get_history_root_dir(); + + // The .fold() at the end creates a new error based on the old one, which + // is not compatible with try_fold() + #[allow(clippy::manual_try_fold)] fs::read_dir(&root) .await .map(ReadDirStream::new) diff --git a/src/command/edit.rs b/src/command/edit.rs index a2623d08..1a054c4c 100644 --- a/src/command/edit.rs +++ b/src/command/edit.rs @@ -1,9 +1,9 @@ use std::{ + io::{stderr, stdin, stdout, IsTerminal}, path::{Path, PathBuf}, process::ExitStatus, }; -use atty::Stream; use tap::TapFallible; use thiserror::Error; use tokio::{fs, io}; @@ -68,8 +68,7 @@ pub(crate) async fn run_edit(path: &Path) -> Result<(), super::Error> { })?; } - let mut cmd = if atty::is(Stream::Stdout) && atty::is(Stream::Stderr) && atty::is(Stream::Stdin) - { + let mut cmd = if stdin().is_terminal() && stderr().is_terminal() && stdout().is_terminal() { open_cmd::open_editor(tmp_file.clone()).map_err(|error| { tracing::error!(%error, "failed to generate CLI editor command"); Error::Start(error) diff --git a/src/config/builder/environment/mod.rs b/src/config/builder/environment/mod.rs index d38d2190..385ef714 100644 --- a/src/config/builder/environment/mod.rs +++ b/src/config/builder/environment/mod.rs @@ -225,7 +225,7 @@ mod tests { path_exists: Some(Combinator(vec![Inner::Single(path_exists.clone())])), }; - let expected = vec![ + let expected = [ format!("({hostname})"), format!("({os})"), format!("({env_var})"), diff --git a/src/config/builder/envtrie.rs b/src/config/builder/envtrie.rs index 036df9fd..242353a2 100644 --- a/src/config/builder/envtrie.rs +++ b/src/config/builder/envtrie.rs @@ -272,7 +272,7 @@ fn get_weighted_map( // Check for cycles, then discard graph tracing::trace!("checking for cycles"); let mut score_dag = DiGraph::::new(); - for list in exclusive_list.iter() { + for list in exclusive_list { let mut prev_idx = None; for name in list.iter().rev() { @@ -430,26 +430,21 @@ impl EnvTrie { .collect::, _>>()?; tracing::trace!("merging trees into a single trie"); - let tree = - nodes - .into_iter() - .fold(Ok(BTreeMap::::new()), |acc, node| { - // TODO: Use result flattening when stable - match acc { - Err(err) => Err(err), - Ok(mut tree) => { - // Explicitly call `drop()` to drop any old value. - match tree.remove(&node.name) { - None => drop(tree.insert(node.name.clone(), node)), - Some(existing) => { - let new_node = existing.merge_with(node)?; - drop(tree.insert(new_node.name.clone(), new_node)); - } - } - Ok(tree) - } + let tree = nodes.into_iter().try_fold( + BTreeMap::::new(), + |mut acc, node| { + // TODO: Use result flattening when stable + // Explicitly call `drop()` to drop any old value. + match acc.remove(&node.name) { + None => drop(acc.insert(node.name.clone(), node)), + Some(existing) => { + let new_node = existing.merge_with(node)?; + drop(acc.insert(new_node.name.clone(), new_node)); } - })?; + } + Ok(acc) + }, + )?; Ok(EnvTrie(tree)) } @@ -476,20 +471,20 @@ impl EnvTrie { .transpose() .map(|path| (env, node, path)) }) - .fold(Ok(None), |acc, (_, node, path)| match (acc, path) { - (Err(err), _) | (_, Err(err)) => Err(err), - (Ok(None), Ok(path)) => Ok(Some((node, path))), - (Ok(Some((acc, acc_path))), Ok(path)) => match acc.score.cmp(&node.score) { - Ordering::Equal => Err(Error::Indecision( - acc.name.clone().into(), - node.name.clone().into(), - )), - Ordering::Less => Ok(Some((node, path))), - Ordering::Greater => Ok(Some((acc, acc_path))), - }, + .try_fold(None, |acc: Option<(&Node, _)>, (_, node, path)| { + match (acc, path) { + (None, path) => Ok(Some((node, path))), + (Some((acc, acc_path)), path) => match acc.score.cmp(&node.score) { + Ordering::Equal => Err(Error::Indecision( + acc.name.clone().into(), + node.name.clone().into(), + )), + Ordering::Less => Ok(Some((node, path))), + Ordering::Greater => Ok(Some((acc, acc_path))), + }, + } })? .map(|(_, path)| path) - .map(Ok) .transpose() } } @@ -549,7 +544,7 @@ mod tests { return false; } - for (key, node1) in tree1.iter() { + for (key, node1) in tree1 { let equal = match tree2.get(key) { None => false, Some(node2) => node_eq_ignore_score(node1, node2), diff --git a/src/config/builder/mod.rs b/src/config/builder/mod.rs index ce097872..bd4adb96 100644 --- a/src/config/builder/mod.rs +++ b/src/config/builder/mod.rs @@ -13,6 +13,7 @@ use tokio::{fs, io}; use environment::Environment; use crate::command::Command; +use crate::config::builder::var_defaults::{EnvVarDefaults, EnvVarDefaultsError}; use crate::hoard::PileConfig; use crate::newtypes::{EnvironmentName, HoardName}; use crate::CONFIG_FILE_STEM; @@ -24,6 +25,7 @@ use self::hoard::Hoard; pub mod environment; pub mod envtrie; pub mod hoard; +pub mod var_defaults; const DEFAULT_CONFIG_EXT: &str = "toml"; /// The items are listed in descending order of precedence @@ -52,9 +54,12 @@ pub enum Error { "configuration file does not have file extension \".toml\", \".yaml\", or \".yml\": {0}" )] InvalidExtension(PathBuf), + /// Failed to set one or more environment variable default. + #[error(transparent)] + EnvVarDefaults(#[from] EnvVarDefaultsError), } -/// Intermediate data structure to build a [`Config`](crate::config::Config). +/// Intermediate data structure to build a [`Config`]. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Parser)] #[clap(author, version, about, long_about = None, rename_all = "kebab")] #[serde(rename_all = "snake_case")] @@ -64,6 +69,9 @@ pub struct Builder { #[serde(rename = "envs")] environments: Option>, #[clap(skip)] + #[serde(default, rename = "defaults")] + var_defaults: EnvVarDefaults, + #[clap(skip)] exclusivity: Option>>, #[clap(long)] data_dir: Option, @@ -112,6 +120,7 @@ impl Builder { hoards: None, config_dir: None, data_dir: None, + var_defaults: EnvVarDefaults::default(), config_file: None, command: None, environments: None, @@ -263,6 +272,8 @@ impl Builder { self = self.set_command(path); } + self.var_defaults.merge_with(other.var_defaults); + self.force = self.force || other.force; self @@ -385,6 +396,8 @@ impl Builder { let force = self.force; tracing::debug!(?force); + self.var_defaults.apply()?; + if let Some(path) = self.config_dir { crate::dirs::set_config_dir(&path); } @@ -395,7 +408,7 @@ impl Builder { if let Some(hoards) = &mut self.hoards { tracing::debug!("layering global config onto hoards"); - for (_, hoard) in hoards.iter_mut() { + for hoard in hoards.values_mut() { hoard.layer_config(self.global_config.as_ref()); } } @@ -430,6 +443,9 @@ mod tests { mod builder { use super::*; + const DEFAULT_VAR: &str = "UNSET"; + const DEFAULT_VAR_VALUE: &str = "no longer unset"; + fn get_default_populated_builder() -> Builder { Builder { config_file: Some(Builder::default_config_file()), @@ -441,6 +457,7 @@ mod tests { hoards: None, force: false, global_config: None, + var_defaults: EnvVarDefaults::default(), } } @@ -457,6 +474,11 @@ mod tests { hoards: None, force: false, global_config: None, + var_defaults: { + let mut defaults = EnvVarDefaults::default(); + defaults.insert(DEFAULT_VAR.into(), DEFAULT_VAR_VALUE.into()); + defaults + }, } } @@ -477,6 +499,7 @@ mod tests { exclusivity: None, force: false, global_config: None, + var_defaults: EnvVarDefaults::default(), }; assert_eq!( @@ -507,16 +530,30 @@ mod tests { #[test] fn layered_builder_prefers_argument_to_self() { - let layer1 = get_default_populated_builder(); - let layer2 = get_non_default_populated_builder(); + let mut layer1 = get_default_populated_builder(); + let mut layer2 = get_non_default_populated_builder(); + + // Add extra env values to ensure they merge properly + layer1.var_defaults.insert("ENV1".into(), "1".into()); + layer1 + .var_defaults + .insert(DEFAULT_VAR.into(), "non default".into()); + layer2.var_defaults.insert("ENV2".into(), "2".into()); + + let mut expected = layer2.clone(); + expected.var_defaults.insert("ENV1".into(), "1".into()); assert_eq!( - layer2, + expected, layer1.clone().layer(layer2.clone()), "layer() should prefer the argument" ); + + let mut expected = layer1.clone(); + expected.var_defaults.insert("ENV2".into(), "2".into()); + assert_eq!( - layer1, + expected, layer2.layer(layer1.clone()), "layer() should prefer the argument" ); @@ -566,5 +603,13 @@ mod tests { assert_eq!(Some(config.config_file), builder.config_file); assert_eq!(Some(config.command), builder.command); } + + #[test] + #[serial_test::serial] + fn builder_sets_env_vars_correctly() { + let builder = get_non_default_populated_builder(); + builder.build().unwrap(); + assert_eq!(std::env::var(DEFAULT_VAR).unwrap(), DEFAULT_VAR_VALUE); + } } } diff --git a/src/config/builder/var_defaults.rs b/src/config/builder/var_defaults.rs new file mode 100644 index 00000000..662a818e --- /dev/null +++ b/src/config/builder/var_defaults.rs @@ -0,0 +1,86 @@ +//! See [`EnvVarDefaults`]. + +use crate::env_vars::StringWithEnv; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fmt::Formatter; +use std::{env, fmt}; + +/// Failed to apply one or more environment variables in [`EnvVarDefaults::apply`]. +/// +/// Most common reasons for this occurring is trying to use an unset variable in a default value, +/// or having two unset variables' values dependent on each other. +#[derive(Debug, thiserror::Error)] +pub struct EnvVarDefaultsError(BTreeMap); + +impl fmt::Display for EnvVarDefaultsError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + assert!(!self.0.is_empty()); + write!(f, "Could not apply environment variable defaults. One or more default values requires an unset variable.")?; + for (var, value) in &self.0 { + write!(f, "\n{var}: {value:?}")?; + } + Ok(()) + } +} + +/// Define variables and their default values, should that variable not otherwise be defined. +/// +/// Variable default values can interpolate the values of other environment variables. +/// See [`StringWithEnv`] for the required syntax. +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +#[serde(transparent)] +#[repr(transparent)] +#[allow(clippy::module_name_repetitions)] +pub struct EnvVarDefaults(BTreeMap); + +impl EnvVarDefaults { + /// Insert a new environment variable/value pairing. + pub fn insert(&mut self, var: String, value: StringWithEnv) -> Option { + self.0.insert(var, value) + } + + /// Merge `other` into `self`. Values in `other` take precedence. + pub fn merge_with(&mut self, other: Self) { + for (var, value) in other.0 { + self.0.insert(var, value); + } + } + + /// Attempt to apply every default value to any unset environment variables, expanding their + /// values first. + /// + /// This will repeatedly attempt to apply variables as long as at least one successfully applies. + /// + /// # Errors + /// + /// See [`EnvVarDefaultsError`]. + pub fn apply(self) -> Result<(), EnvVarDefaultsError> { + // Add one just so the `while` condition is true once. + let mut remaining_last_loop = self.0.len() + 1; + let mut this_loop = self.0; + + while remaining_last_loop != this_loop.len() { + let last_loop = std::mem::take(&mut this_loop); + remaining_last_loop = last_loop.len(); + for (var, value) in last_loop { + if env::var_os(&var).is_none() { + match value.clone().process() { + Err(_) => _ = this_loop.insert(var, value), + Ok(value) => { + // This function can panic under certain circumstances. Either check for + // them or catch the panic. + env::set_var(var, value); + } + } + } + } + } + + if this_loop.is_empty() { + Ok(()) + } else { + Err(EnvVarDefaultsError(this_loop)) + } + } +} diff --git a/src/env_vars.rs b/src/env_vars.rs index 213f4c84..c0f8ab52 100644 --- a/src/env_vars.rs +++ b/src/env_vars.rs @@ -12,7 +12,7 @@ use std::{env, fmt}; // // The `+?` is non-greedy matching, which is necessary for if there are multiple variables. static ENV_REGEX: Lazy = Lazy::new(|| { - Regex::new(r#"\$\{[^(=|\x{0}|$)]+?}"#).expect("failed to compile regular expression") + Regex::new(r"\$\{[^(=|\x{0}|$)]+?}").expect("failed to compile regular expression") }); /// An error that may occur during expansion. @@ -61,73 +61,42 @@ impl std::error::Error for Error { } } -/// A [`String`] representing a path that may contain one or more environment variables to be -/// expanded. +/// A [`String`] that may contain one or more environment variables to be expanded. #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[repr(transparent)] #[serde(transparent)] -pub struct PathWithEnv(String); +pub struct StringWithEnv(String); -impl From for PathWithEnv { +impl From for StringWithEnv { fn from(s: String) -> Self { Self(s) } } -impl From<&str> for PathWithEnv { +impl From<&str> for StringWithEnv { fn from(s: &str) -> Self { Self::from(s.to_string()) } } -impl fmt::Display for PathWithEnv { +impl fmt::Display for StringWithEnv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -/// Takes the input string, expands all environment variables, and returns the -/// expanded string as a [`PathBuf`]. -/// -/// # Example -/// -/// ``` -/// use std::path::PathBuf; -/// use hoard::env_vars::PathWithEnv; -/// use hoard::paths::SystemPath; -/// -/// #[cfg(unix)] -/// let template = "/some/${CUSTOM_VAR}/path"; -/// #[cfg(windows)] -/// let template = "C:/some/${CUSTOM_VAR}/path"; -/// std::env::set_var("CUSTOM_VAR", "foobar"); -/// let path = PathWithEnv::from(template) -/// .process() -/// .expect("failed to expand path"); -/// #[cfg(unix)] -/// let expected = SystemPath::try_from(PathBuf::from("/some/foobar/path")).unwrap(); -/// #[cfg(windows)] -/// let expected = SystemPath::try_from(PathBuf::from("C:/some/foobar/path")).unwrap(); -/// assert_eq!(path, expected); -/// ``` -/// -/// # Errors -/// -/// - Any [`VarError`](env::VarError) from looking up the environment variable's value. -impl PathWithEnv { - /// Replace any environment variables with their associated values and attempt to convert - /// into a [`SystemPath`]. +impl StringWithEnv { + /// Replace any environment variables with their associated values. /// /// # Errors /// /// See [`Error`] - #[tracing::instrument(level = "debug", name = "process_path_with_env")] - pub fn process(self) -> Result { - let mut new_path = self.0; + pub fn process(self) -> Result { + let mut new_string = self.0; let mut start: usize = 0; let mut old_start: usize; - while let Some(mat) = ENV_REGEX.find(&new_path[start..]) { + while let Some(mat) = ENV_REGEX.find(&new_string[start..]) { let var = mat.as_str(); let var = &var[2..var.len() - 1]; tracing::trace!(var, "found environment variable {}", var,); @@ -143,25 +112,65 @@ impl PathWithEnv { old_start = start; start += mat.start() + value.len(); - if start > (new_path.len() + value.len() - mat.as_str().len()) { - start = new_path.len(); + if start > (new_string.len() + value.len() - mat.as_str().len()) { + start = new_string.len(); } let range = mat.range(); // grcov: ignore-start tracing::trace!( var, - path = %new_path, + path = %new_string, %value, "expanding first instance of variable in path" ); // grcov: ignore-end - new_path.replace_range(range.start + old_start..range.end + old_start, &value); - if start >= new_path.len() { + new_string.replace_range(range.start + old_start..range.end + old_start, &value); + if start >= new_string.len() { break; } } + Ok(new_string) + } +} + +/// A [`String`] representing a path that may contain one or more environment variables to be +/// expanded. +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[repr(transparent)] +#[serde(transparent)] +pub struct PathWithEnv(String); + +impl From for PathWithEnv { + fn from(s: String) -> Self { + Self(s) + } +} + +impl From<&str> for PathWithEnv { + fn from(s: &str) -> Self { + Self::from(s.to_string()) + } +} + +impl fmt::Display for PathWithEnv { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PathWithEnv { + /// Replace any environment variables with their associated values and attempt to convert + /// into a [`SystemPath`]. + /// + /// # Errors + /// + /// See [`Error`] + #[tracing::instrument(level = "debug", name = "process_path_with_env")] + pub fn process(self) -> Result { + let new_path = StringWithEnv(self.0).process()?; + // Splitting into components and collecting will collapse multiple separators. SystemPath::try_from(PathBuf::from(new_path).components().collect::()) .map_err(Error::Path) diff --git a/src/lib.rs b/src/lib.rs index 4b6e7600..ef889eff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,8 @@ #![deny(clippy::complexity)] #![deny(clippy::perf)] #![deny(clippy::pedantic)] -#![deny(rustdoc::missing_doc_code_examples)] +// See https://github.com/rust-lang/rust/issues/87858 +//#![deny(rustdoc::missing_doc_code_examples)] #![deny( absolute_paths_not_starting_with_crate, anonymous_parameters, diff --git a/src/newtypes/pile_name.rs b/src/newtypes/pile_name.rs index ce6456d6..2583908b 100644 --- a/src/newtypes/pile_name.rs +++ b/src/newtypes/pile_name.rs @@ -1,5 +1,5 @@ +use std::fmt; use std::str::FromStr; -use std::{fmt, ops::Deref}; use serde::{de, Deserialize, Deserializer, Serialize}; @@ -101,17 +101,9 @@ impl From for Option { } } -impl Deref for PileName { - type Target = Option; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - impl fmt::Display for PileName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.as_deref() { + match self.as_ref() { None => write!(f, ""), Some(name) => write!(f, "{name}"), } @@ -268,14 +260,6 @@ mod tests { ); } - #[test] - #[allow(clippy::explicit_deref_methods)] - fn test_deref() { - let name: PileName = "testing".parse().unwrap(); - assert_eq!(&name.0, name.deref()); - assert_eq!(&None, PileName::anonymous().deref()); - } - #[test] fn test_to_string() { assert_eq!("", PileName::anonymous().to_string()); diff --git a/src/paths.rs b/src/paths.rs index 5c2a4f73..84112343 100644 --- a/src/paths.rs +++ b/src/paths.rs @@ -168,6 +168,7 @@ impl HoardPath { /// use it as the prefix directory for a [`RelativePath`]. It is up to the caller to make /// sure the resulting path is valid for use. #[must_use] + #[allow(clippy::missing_panics_doc)] pub fn join(&self, rhs: &RelativePath) -> Self { Self::try_from( rhs.0 @@ -227,6 +228,7 @@ impl SystemPath { /// use it as the prefix directory for a [`RelativePath`]. It is up to the caller to make /// sure the resulting path is valid for use. #[must_use] + #[allow(clippy::missing_panics_doc)] pub fn join(&self, rhs: &RelativePath) -> Self { Self::try_from( rhs.0 @@ -327,7 +329,7 @@ impl From<&HoardName> for RelativePath { impl From<&PileName> for RelativePath { fn from(name: &PileName) -> Self { - RelativePath(name.as_deref().map(PathBuf::from)) + RelativePath(name.as_str().map(PathBuf::from)) } }