mirror of
https://github.com/Zenithsiz/zbuild.git
synced 2026-02-03 14:10:02 +00:00
Merge branch 'dev'
This commit is contained in:
commit
7e32620e16
15
CHANGELOG
Normal file
15
CHANGELOG
Normal file
@ -0,0 +1,15 @@
|
||||
# 0.1.2
|
||||
|
||||
## Major
|
||||
|
||||
- Added commands within commands. Arguments to commands may now be commands themselves. The stdout of the command will be captured and passed as the argument.
|
||||
|
||||
- (BREAKING) Working directory is now for each command, rather than for the executable section
|
||||
|
||||
## Minor
|
||||
|
||||
- (BREAKING) Option `--file-log` is now `--log-file`
|
||||
|
||||
- Parent directories of built files now watched to ensure that deleted files are still properly watched.
|
||||
|
||||
This may cause some slowdowns if you're watching a file in a directory with a lot of movement, but it otherwise fixes some files randomly not being watched.
|
||||
394
Cargo.lock
generated
394
Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@ -19,24 +19,23 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
|
||||
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
@ -53,24 +52,24 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
@ -84,9 +83,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
|
||||
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -101,9 +100,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
@ -122,21 +121,24 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.3"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[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"
|
||||
@ -146,20 +148,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.3.10"
|
||||
version = "4.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
|
||||
checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.3.10"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
|
||||
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -169,9 +170,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",
|
||||
@ -181,9 +182,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"
|
||||
@ -212,12 +213,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.4.0"
|
||||
version = "5.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown 0.12.3",
|
||||
"hashbrown",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
@ -231,30 +232,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
@ -264,23 +244,23 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "file-id"
|
||||
version = "0.1.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13be71e6ca82e91bc0cb862bebaac0b2d1924a5a1d970c822b2f98b63fda8c3"
|
||||
checksum = "6584280525fb2059cba3db2c04abf947a1a29a45ddae89f3870f8281704fafc9"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.21"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"windows-sys 0.48.0",
|
||||
"redox_syscall",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -383,15 +363,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
@ -407,9 +381,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
@ -418,7 +392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -441,17 +415,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
@ -463,9 +426,9 @@ dependencies = [
|
||||
|
||||
[[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 = "kqueue"
|
||||
@ -499,12 +462,6 @@ version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
@ -517,9 +474,9 @@ dependencies = [
|
||||
|
||||
[[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 = "matchers"
|
||||
@ -532,9 +489,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
@ -554,35 +511,37 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "6.0.1"
|
||||
version = "6.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5738a2795d57ea20abec2d6d76c6081186709c0024187cd5977265eda6598b51"
|
||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.0",
|
||||
"crossbeam-channel",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-debouncer-full"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "416969970ec751a5d702a88c6cd19ac1332abe997fce43f96db0418550426241"
|
||||
checksum = "49f5dab59c348b9b50cf7f261960a20e389feb2713636399cd9082cd4b536154"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"file-id",
|
||||
"log",
|
||||
"notify",
|
||||
"parking_lot",
|
||||
"walkdir",
|
||||
@ -615,9 +574,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.31.1"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -652,25 +611,25 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.1",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.1"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e138fdd8263907a2b0e1b4e80b7e58c721126479b6e6eedfb1b402acea7b9bd"
|
||||
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.1"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1fef411b303e3e12d534fb6e7852de82da56edd937d895125821fb7c09436c7"
|
||||
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -679,9 +638,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"
|
||||
@ -691,31 +650,22 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.29"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
@ -761,24 +711,11 @@ version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[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 = "same-file"
|
||||
@ -791,24 +728,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
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",
|
||||
@ -817,9 +754,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.22"
|
||||
version = "0.9.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85"
|
||||
checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
@ -857,18 +794,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -879,9 +816,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.22"
|
||||
version = "2.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -890,18 +827,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.40"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -920,11 +857,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.29.1"
|
||||
version = "1.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
|
||||
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
@ -935,7 +871,7 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1024,15 +960,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[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 = "utf8parse"
|
||||
@ -1093,141 +1029,75 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.1",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "zbuild"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-broadcast",
|
||||
|
||||
43
Cargo.toml
43
Cargo.toml
@ -1,45 +1,45 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "zbuild"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Futures
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
tokio = { version = "1.32.0", features = ["full"] }
|
||||
tokio-stream = "0.1.14"
|
||||
async-broadcast = "0.5.1"
|
||||
async-recursion = "1.0.4"
|
||||
async-recursion = "1.0.5"
|
||||
futures = "0.3.28"
|
||||
|
||||
# Concurrency
|
||||
dashmap = "5.4.0"
|
||||
dashmap = "5.5.3"
|
||||
|
||||
# Cmd
|
||||
clap = { version = "4.3.10", features = ["derive"] }
|
||||
clap = { version = "4.4.3", features = ["derive"] }
|
||||
|
||||
# Logging
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
|
||||
# Error handling
|
||||
anyhow = "1.0.71"
|
||||
thiserror = "1.0.40"
|
||||
anyhow = "1.0.75"
|
||||
thiserror = "1.0.48"
|
||||
|
||||
# Serde
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
serde_yaml = "0.9.22"
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
serde_yaml = "0.9.25"
|
||||
|
||||
# File system
|
||||
notify = "6.0.1"
|
||||
notify-debouncer-full = "0.2.0"
|
||||
filetime = "0.2.21"
|
||||
notify = "6.1.1"
|
||||
notify-debouncer-full = "0.3.1"
|
||||
filetime = "0.2.22"
|
||||
|
||||
|
||||
# Util
|
||||
itertools = "0.11.0"
|
||||
npath = { git = "https://github.com/gdzx/npath", rev = "00acdd2974bb1682b6d1dcc6f0ea7cd54da42381" }
|
||||
pin-project = "1.1.1"
|
||||
pin-project = "1.1.3"
|
||||
|
||||
[lints]
|
||||
|
||||
@ -102,8 +102,15 @@ clippy.unreachable = "allow"
|
||||
clippy.mem_forget = "allow"
|
||||
clippy.shadow_same = "allow"
|
||||
clippy.shadow_reuse = "allow"
|
||||
clippy.shadow_unrelated = "allow" # TODO: Maybe check this one every once in a while? Pretty noisy though
|
||||
clippy.wildcard_enum_match_arm = "allow"
|
||||
clippy.shadow_unrelated = "allow" # TODO: Maybe check this one every once in a while? Pretty noisy though
|
||||
clippy.min_ident_chars = "allow" # Useful for generics such as `f: impl FnOnce()`
|
||||
clippy.single_call_fn = "allow" # It's still useful to separate blocks of code into functions
|
||||
clippy.float_arithmetic = "allow"
|
||||
clippy.default_numeric_fallback = "allow" # TODO: This isn't very useful for floats, but might be for integers
|
||||
|
||||
# We prefer the short version
|
||||
clippy.pub_with_shorthand = "allow"
|
||||
clippy.pub_without_shorthand = "warn"
|
||||
|
||||
# Triggers in macro-generated code
|
||||
# TODO: Turn these on once they don't trigger in macro-generated code
|
||||
@ -118,6 +125,7 @@ clippy.missing_const_for_fn = "allow"
|
||||
clippy.significant_drop_in_scrutinee = "allow"
|
||||
clippy.significant_drop_tightening = "allow"
|
||||
clippy.tests_outside_test_module = "allow" # Triggers for benches
|
||||
clippy.multiple_unsafe_ops_per_block = "allow" # Triggers for async?
|
||||
|
||||
# Style
|
||||
clippy.implicit_return = "allow"
|
||||
@ -134,8 +142,6 @@ clippy.separated_literal_suffix = "allow"
|
||||
# Matching on a vale and adding `ref` is easier than matching on ref and de-referencing values within the body
|
||||
clippy.ref_patterns = "allow"
|
||||
clippy.semicolon_outside_block = "allow"
|
||||
clippy.manual_let_else = "allow" # Rustfmt doesn't support let-else yet
|
||||
|
||||
|
||||
# Performance of floats isn't paramount
|
||||
clippy.suboptimal_flops = "allow"
|
||||
@ -175,3 +181,6 @@ clippy.missing_trait_methods = "allow"
|
||||
# We only panic when it's an unrecoverable error
|
||||
clippy.unwrap_in_result = "allow"
|
||||
clippy.panic_in_result_fn = "allow"
|
||||
|
||||
# Sometimes small structs defined inline don't need documentation
|
||||
clippy.missing_docs_in_private_items = "allow"
|
||||
|
||||
59
GUIDE.md
59
GUIDE.md
@ -154,7 +154,7 @@ You may specify the execution as either:
|
||||
|
||||
You may not specify any options (such as the working directory) using this form
|
||||
|
||||
```
|
||||
```yaml
|
||||
exec:
|
||||
- [bash, ...]
|
||||
- [cp, ...]
|
||||
@ -163,17 +163,60 @@ You may specify the execution as either:
|
||||
|
||||
2. Full form
|
||||
|
||||
The full form allow you to fully specify everything, but you must put the commands within an inner `cmds` key.
|
||||
The full form allow you to fully specify everything, but you must put the arguments of each command within an inner `args` key.
|
||||
|
||||
```
|
||||
```yaml
|
||||
exec:
|
||||
cwd: "..."
|
||||
cmds:
|
||||
- [bash, ...]
|
||||
- [cp, ...]
|
||||
- ...
|
||||
- cwd: "..."
|
||||
args: [bash, ...]
|
||||
- [cp, ...]
|
||||
- ...
|
||||
```
|
||||
|
||||
Each argument may also be a command. The `stdout` of the sub-command will be passed as the argument to the parent command. Supports the following versions:
|
||||
|
||||
1. Short form
|
||||
|
||||
Similarly to top-level exec, you may just specify an array
|
||||
|
||||
```yaml
|
||||
exec:
|
||||
- - cat
|
||||
- pwd: ".."
|
||||
args: [find, ".", -iname, "myfile.txt"]
|
||||
```
|
||||
|
||||
2. Long form
|
||||
|
||||
```yaml
|
||||
exec:
|
||||
- - cat
|
||||
- strip_on_fail: false
|
||||
cmd:
|
||||
pwd: ".."
|
||||
args: [find, ".", -iname, "myfile.txt"]
|
||||
```
|
||||
|
||||
3. Special case for `strip_on_fail`
|
||||
|
||||
```yaml
|
||||
exec:
|
||||
- - cat
|
||||
- strip_on_fail:
|
||||
pwd: ".."
|
||||
args: [find, ".", -iname, "myfile.txt"]
|
||||
```
|
||||
|
||||
`strip_on_fail` will strip the argument if the command within it fails. This is useful for optional arguments.
|
||||
|
||||
The example uses the full syntax for the inner command, but you can use the short syntax. For example the following works:
|
||||
|
||||
```yaml
|
||||
exec:
|
||||
- - cat
|
||||
- [find, ".", -iname, "myfile.txt"]
|
||||
```
|
||||
|
||||
## Aliases
|
||||
|
||||
You may define aliases (either global or rule-scoped) which give a name to a value.
|
||||
|
||||
7
clippy.toml
Normal file
7
clippy.toml
Normal file
@ -0,0 +1,7 @@
|
||||
absolute-paths-allowed-crates = [
|
||||
# `tracing_subscriber::fmt` would be easily confused with `std::fmt`
|
||||
"tracing_subscriber",
|
||||
# TODO: Review these?
|
||||
"futures",
|
||||
"notify",
|
||||
]
|
||||
@ -49,7 +49,7 @@ pub struct Args {
|
||||
|
||||
/// Watcher file event debouncer timeout
|
||||
#[clap(long = "watcher-debouncer-timeout-ms")]
|
||||
pub watch_debouncer_timeout_ms: Option<f64>,
|
||||
pub watcher_debouncer_timeout_ms: Option<f64>,
|
||||
|
||||
/// Logs output to a file.
|
||||
///
|
||||
|
||||
82
src/ast.rs
82
src/ast.rs
@ -244,7 +244,6 @@ impl<'a, 'de: 'a> serde::Deserialize<'de> for Expr<'a> {
|
||||
}
|
||||
|
||||
// Then check if it was an alias or pattern
|
||||
#[expect(clippy::missing_docs_in_private_items)]
|
||||
enum Kind {
|
||||
Alias,
|
||||
Pattern,
|
||||
@ -344,38 +343,63 @@ pub struct Rule<'a> {
|
||||
}
|
||||
|
||||
/// Execution
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Exec<'a> {
|
||||
/// Only commands
|
||||
OnlyCmds(Vec<Command<'a>>),
|
||||
|
||||
/// Full
|
||||
Full {
|
||||
/// working directory
|
||||
#[serde(default)]
|
||||
#[serde(borrow)]
|
||||
cwd: Option<Expr<'a>>,
|
||||
|
||||
/// Commands
|
||||
cmds: Vec<Command<'a>>,
|
||||
},
|
||||
#[serde(transparent)]
|
||||
pub struct Exec<'a> {
|
||||
/// Commands
|
||||
#[serde(borrow)]
|
||||
pub cmds: Vec<Command<'a>>,
|
||||
}
|
||||
|
||||
impl Default for Exec<'_> {
|
||||
fn default() -> Self {
|
||||
Self::OnlyCmds(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Command
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Command<'a> {
|
||||
/// All arguments
|
||||
#[serde(borrow)]
|
||||
pub args: Vec<Expr<'a>>,
|
||||
#[serde(untagged)]
|
||||
pub enum Command<'a> {
|
||||
/// Only arguments
|
||||
OnlyArgs(Vec<CommandArg<'a>>),
|
||||
|
||||
/// Full
|
||||
Full {
|
||||
/// Working directory
|
||||
#[serde(default)]
|
||||
#[serde(borrow)]
|
||||
cwd: Option<Expr<'a>>,
|
||||
|
||||
/// Arguments
|
||||
args: Vec<CommandArg<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Command argument
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CommandArg<'a> {
|
||||
/// Expression
|
||||
#[serde(borrow)]
|
||||
Expr(Expr<'a>),
|
||||
|
||||
/// Command
|
||||
#[serde(borrow)]
|
||||
Command(Command<'a>),
|
||||
|
||||
/// Command full
|
||||
CommandFull {
|
||||
/// Strip the command if failed
|
||||
strip_on_fail: bool,
|
||||
|
||||
/// Command
|
||||
#[serde(borrow)]
|
||||
cmd: Command<'a>,
|
||||
},
|
||||
|
||||
/// Strip on fail
|
||||
StripOnFail {
|
||||
/// Command
|
||||
#[serde(rename = "strip_on_fail")]
|
||||
#[serde(borrow)]
|
||||
cmd: Command<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
153
src/build.rs
153
src/build.rs
@ -16,22 +16,24 @@ use {
|
||||
match_expr::match_expr,
|
||||
},
|
||||
crate::{
|
||||
rules::{DepItem, Expr, OutItem, Rule, Target},
|
||||
rules::{Command, CommandArg, DepItem, Expr, OutItem, Rule, Target},
|
||||
util::{self, CowStr},
|
||||
AppError,
|
||||
Expander,
|
||||
Rules,
|
||||
},
|
||||
anyhow::Context,
|
||||
dashmap::DashMap,
|
||||
filetime::FileTime,
|
||||
futures::{stream::FuturesUnordered, StreamExt, TryStreamExt},
|
||||
itertools::Itertools,
|
||||
std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
mem,
|
||||
time::{Duration, SystemTime},
|
||||
},
|
||||
tokio::{fs, process::Command, sync::Semaphore},
|
||||
tokio::{fs, process, sync::Semaphore},
|
||||
};
|
||||
|
||||
// TODO: If the user zbuild file is not generated properly, it can
|
||||
@ -73,7 +75,7 @@ pub struct Builder<'s> {
|
||||
_event_rx: async_broadcast::InactiveReceiver<Event<'s>>,
|
||||
|
||||
/// Expander
|
||||
expander: Expander,
|
||||
expander: Expander<'s>,
|
||||
|
||||
/// All rules' build lock
|
||||
rules_lock: DashMap<TargetRule<'s>, BuildLock<'s>>,
|
||||
@ -110,7 +112,9 @@ impl<'s> Builder<'s> {
|
||||
// Note: We only send them if there are any receivers (excluding ours, which is inactive),
|
||||
// to ensure we don't deadlock waiting for someone to read the events
|
||||
if self.event_tx.receiver_count() > 0 {
|
||||
self.event_tx
|
||||
// Note: We don't care about the event
|
||||
let _: Option<Event<'_>> = self
|
||||
.event_tx
|
||||
.broadcast(make_event())
|
||||
.await
|
||||
.expect("Event channel was closed");
|
||||
@ -171,7 +175,9 @@ impl<'s> Builder<'s> {
|
||||
/// Resets a build
|
||||
pub async fn reset_build(&self, target: &Target<'s, CowStr<'s>>, rules: &Rules<'s>) -> Result<(), AppError> {
|
||||
// Get the rule for the target
|
||||
let Some((_, target_rule)) = self.target_rule(target, rules)? else { return Ok(()) };
|
||||
let Some((_, target_rule)) = self.target_rule(target, rules)? else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Get the built lock, or create it
|
||||
// Note: Important to clone since we'll be `await`ing with it.
|
||||
@ -223,9 +229,8 @@ impl<'s> Builder<'s> {
|
||||
};
|
||||
|
||||
// Get the rule for the target
|
||||
let (rule, target_rule) = match self.target_rule(&target, rules)? {
|
||||
Some((rule, target_rule)) => (rule, target_rule),
|
||||
None => match target {
|
||||
let Some((rule, target_rule)) = self.target_rule(&target, rules)? else {
|
||||
match target {
|
||||
Target::File { ref file, .. } => match fs::metadata(&**file).await {
|
||||
Ok(metadata) => {
|
||||
let build_time = self::file_modified_time(metadata);
|
||||
@ -260,7 +265,7 @@ impl<'s> Builder<'s> {
|
||||
},
|
||||
// Note: If `target_rule` returns `Err` if this was a rule, so we can never reach here
|
||||
Target::Rule { .. } => unreachable!(),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Get the built lock, or create it
|
||||
@ -311,7 +316,6 @@ impl<'s> Builder<'s> {
|
||||
) -> Result<BuildResult, AppError> {
|
||||
/// Dependency
|
||||
#[derive(Clone, Debug)]
|
||||
#[expect(clippy::missing_docs_in_private_items)]
|
||||
enum Dep<'s, 'a> {
|
||||
/// File
|
||||
File {
|
||||
@ -455,6 +459,7 @@ impl<'s> Builder<'s> {
|
||||
};
|
||||
|
||||
// If the dependency if a dependency deps file or an output deps file (and exists), build it's dependencies too
|
||||
#[allow(clippy::wildcard_enum_match_arm, reason = "We only care about some variants")]
|
||||
let dep_deps = match &dep {
|
||||
Dep::File {
|
||||
file,
|
||||
@ -619,41 +624,107 @@ impl<'s> Builder<'s> {
|
||||
/// Rebuilds a rule
|
||||
pub async fn rebuild_rule(&self, rule: &Rule<'s, CowStr<'s>>) -> Result<(), AppError> {
|
||||
// Lock the semaphore
|
||||
let _permit = self.exec_semaphore.acquire().await;
|
||||
let _permit = self
|
||||
.exec_semaphore
|
||||
.acquire()
|
||||
.await
|
||||
.context("Executable semaphore was closed")
|
||||
.map_err(AppError::Other)?;
|
||||
|
||||
for cmd in &rule.exec.cmds {
|
||||
let (program, args) = cmd.args.split_first().ok_or_else(|| AppError::RuleExecEmpty {
|
||||
rule_name: rule.name.to_owned(),
|
||||
})?;
|
||||
|
||||
// Create the command
|
||||
let mut os_cmd = Command::new(&**program);
|
||||
os_cmd.args(args.iter().map(|arg| &**arg));
|
||||
|
||||
// Set the working directory, if we have any
|
||||
if let Some(cwd) = &rule.exec.cwd {
|
||||
os_cmd.current_dir(&**cwd);
|
||||
}
|
||||
|
||||
// Then spawn it and measure
|
||||
tracing::debug!(target: "zbuild_exec", "{} {}", program, args.join(" "));
|
||||
let (duration, ()) = util::try_measure_async(async {
|
||||
os_cmd
|
||||
.spawn()
|
||||
.map_err(AppError::spawn_command(cmd))?
|
||||
.wait()
|
||||
.await
|
||||
.map_err(AppError::wait_command(cmd))?
|
||||
.exit_ok()
|
||||
.map_err(AppError::command_failed(cmd))
|
||||
})
|
||||
.await?;
|
||||
tracing::trace!(target: "zbuild_exec", rule_name=?rule.name, ?program, ?args, ?duration, "Execution duration");
|
||||
// Note: We don't care about the stdout here and don't capture it anyway.
|
||||
let _: String = self.exec_cmd(rule.name, cmd, false).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Executes a command, returning it's stdout
|
||||
#[expect(unused_results, reason = "Due to the builder pattern of `Command`")]
|
||||
#[expect(clippy::only_used_in_recursion, reason = "It might be used in the future")]
|
||||
#[async_recursion::async_recursion]
|
||||
async fn exec_cmd(
|
||||
&self,
|
||||
rule_name: &str,
|
||||
cmd: &Command<CowStr<'s>>,
|
||||
capture_stdout: bool,
|
||||
) -> Result<String, AppError> {
|
||||
// Process all arguments
|
||||
// Note: When recursing, always capture stdout
|
||||
let args = cmd
|
||||
.args
|
||||
.iter()
|
||||
.map(async move |arg| match arg {
|
||||
CommandArg::Expr(arg) => Ok(Some(Cow::Borrowed(&**arg))),
|
||||
CommandArg::Command { strip_on_fail, cmd } => {
|
||||
let res = self.exec_cmd(rule_name, cmd, true).await;
|
||||
match (res, strip_on_fail) {
|
||||
(Ok(arg), _) => Ok(Some(Cow::Owned(arg))),
|
||||
(Err(err), true) => {
|
||||
tracing::debug!(?arg, ?err, "Stripping argument from failure");
|
||||
Ok(None)
|
||||
},
|
||||
(Err(err), false) => Err(err),
|
||||
}
|
||||
},
|
||||
})
|
||||
.enumerate()
|
||||
.map(async move |(idx, fut)| fut.await.map(|arg| (idx, arg)))
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.try_collect::<Vec<_>>()
|
||||
.await?
|
||||
.into_iter()
|
||||
.sorted_by_key(|&(idx, _)| idx)
|
||||
.filter_map(|(_, arg)| arg)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (program, args) = args.split_first().ok_or_else(|| AppError::RuleExecEmpty {
|
||||
rule_name: rule_name.to_owned(),
|
||||
})?;
|
||||
|
||||
// Create the command
|
||||
let mut os_cmd = process::Command::new(&**program);
|
||||
os_cmd.args(args.iter().map(|arg| &**arg));
|
||||
|
||||
// Set the working directory, if we have any
|
||||
if let Some(cwd) = &cmd.cwd {
|
||||
os_cmd.current_dir(&**cwd);
|
||||
}
|
||||
|
||||
// If we capture pipe stdout, do it
|
||||
if capture_stdout {
|
||||
#[expect(
|
||||
clippy::absolute_paths,
|
||||
reason = "We're already using a `process` (`tokio::process`)"
|
||||
)]
|
||||
os_cmd.stdout(std::process::Stdio::piped());
|
||||
}
|
||||
|
||||
// Then spawn it and measure
|
||||
tracing::debug!(target: "zbuild_exec", "{} {}", program, args.join(" "));
|
||||
let (duration, stdout) = util::try_measure_async(async {
|
||||
let output = os_cmd
|
||||
.spawn()
|
||||
.map_err(AppError::spawn_command(cmd))?
|
||||
.wait_with_output()
|
||||
.await
|
||||
.map_err(AppError::wait_command(cmd))?;
|
||||
|
||||
output.status.exit_ok().map_err(AppError::command_failed(cmd))?;
|
||||
Ok(output.stdout)
|
||||
})
|
||||
.await?;
|
||||
tracing::trace!(target: "zbuild_exec", ?rule_name, ?program, ?args, ?duration, "Execution duration");
|
||||
|
||||
// Finally parse stdout
|
||||
// TODO: Not require utf8?
|
||||
let stdout = String::from_utf8(stdout)
|
||||
.context("Stdout was non-utf8")
|
||||
.map_err(AppError::Other)?;
|
||||
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
/// Finds a rule for `file`
|
||||
// TODO: Not make this `O(N)` for the number of rules.
|
||||
#[expect(clippy::type_complexity)] // TODO: Add some type aliases / struct
|
||||
@ -734,7 +805,11 @@ async fn rule_last_build_time<'s>(rule: &Rule<'s, CowStr<'s>>) -> Result<Option<
|
||||
}
|
||||
|
||||
/// Returns the file modified time
|
||||
#[expect(clippy::needless_pass_by_value)] // We use it in `.map`, which makes it convenient to receive by value
|
||||
#[expect(
|
||||
clippy::needless_pass_by_value,
|
||||
reason = "We use it in `.map`, which makes it convenient to receive by value"
|
||||
)]
|
||||
#[expect(clippy::absolute_paths, reason = "We're already using a `fs` (`tokio::fs`)")]
|
||||
fn file_modified_time(metadata: std::fs::Metadata) -> SystemTime {
|
||||
let file_time = FileTime::from_last_modification_time(&metadata);
|
||||
let unix_offset = Duration::new(
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// Imports
|
||||
use {
|
||||
crate::{rules::Target, util::CowStr, AppError},
|
||||
std::{collections::HashMap, sync::Arc, time::SystemTime},
|
||||
std::{assert_matches::assert_matches, collections::HashMap, sync::Arc, time::SystemTime},
|
||||
tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock},
|
||||
};
|
||||
|
||||
@ -100,7 +100,8 @@ impl<'s> BuildLockBuildGuard<'s> {
|
||||
|
||||
/// Resets this build.
|
||||
pub fn reset(&mut self, target: &Target<'s, CowStr<'s>>) {
|
||||
self.state.targets_res.remove(target);
|
||||
// Note: We don't care about the previous build result
|
||||
let _: Option<Result<BuildResult, _>> = self.state.targets_res.remove(target);
|
||||
}
|
||||
|
||||
/// Finishes a build
|
||||
@ -110,7 +111,8 @@ impl<'s> BuildLockBuildGuard<'s> {
|
||||
res: Result<BuildResult, AppError>,
|
||||
) -> Result<BuildResult, AppError> {
|
||||
let res = res.map_err(Arc::new);
|
||||
self.state.targets_res.insert(target.clone(), res.clone());
|
||||
let prev_res = self.state.targets_res.insert(target.clone(), res.clone());
|
||||
assert_matches!(prev_res, None, "Build was already finished");
|
||||
res.map_err(AppError::Shared)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ use {
|
||||
util::CowStr,
|
||||
AppError,
|
||||
},
|
||||
std::collections::HashMap,
|
||||
std::{assert_matches::assert_matches, collections::HashMap},
|
||||
};
|
||||
|
||||
/// Returns if `value` matches all `cmpts` and returns all patterns resolved
|
||||
@ -65,7 +65,8 @@ pub fn match_expr<'s>(
|
||||
|
||||
// If we get here, match everything
|
||||
// TODO: Borrow some cases?
|
||||
patterns.insert(CowStr::Borrowed(pat.name), CowStr::Owned(value.to_owned()));
|
||||
let prev_value = patterns.insert(CowStr::Borrowed(pat.name), CowStr::Owned(value.to_owned()));
|
||||
assert_matches!(prev_value, None, "Found repeated pattern");
|
||||
cur_cmpts = &[];
|
||||
value = "";
|
||||
},
|
||||
|
||||
21
src/error.rs
21
src/error.rs
@ -2,7 +2,7 @@
|
||||
|
||||
// Imports
|
||||
use {
|
||||
crate::rules::{AliasOp, Command, Expr, Target},
|
||||
crate::rules::{self, AliasOp, Command, Expr, Target},
|
||||
itertools::Itertools,
|
||||
std::{fmt, io, path::PathBuf, process::ExitStatusError, sync::Arc},
|
||||
};
|
||||
@ -374,7 +374,7 @@ impl AppError {
|
||||
/// Returns a function to create a [`Self::SpawnCommand`] error from it's inner error.
|
||||
pub fn spawn_command<T: fmt::Display>(cmd: &Command<T>) -> impl FnOnce(io::Error) -> Self + '_ {
|
||||
move |err| Self::SpawnCommand {
|
||||
cmd_fmt: cmd.args.iter().join(" "),
|
||||
cmd_fmt: Self::cmd_to_string(cmd),
|
||||
err,
|
||||
}
|
||||
}
|
||||
@ -382,7 +382,7 @@ impl AppError {
|
||||
/// Returns a function to create a [`Self::WaitCommand`] error from it's inner error.
|
||||
pub fn wait_command<T: fmt::Display>(cmd: &Command<T>) -> impl FnOnce(io::Error) -> Self + '_ {
|
||||
move |err| Self::WaitCommand {
|
||||
cmd_fmt: cmd.args.iter().join(" "),
|
||||
cmd_fmt: Self::cmd_to_string(cmd),
|
||||
err,
|
||||
}
|
||||
}
|
||||
@ -390,11 +390,24 @@ impl AppError {
|
||||
/// Returns a function to create a [`Self::CommandFailed`] error from it's inner error.
|
||||
pub fn command_failed<T: fmt::Display>(cmd: &Command<T>) -> impl FnOnce(ExitStatusError) -> Self + '_ {
|
||||
move |err| Self::CommandFailed {
|
||||
cmd_fmt: cmd.args.iter().join(" "),
|
||||
cmd_fmt: Self::cmd_to_string(cmd),
|
||||
err,
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to format a `Command` for errors
|
||||
fn cmd_to_string<T: fmt::Display>(cmd: &Command<T>) -> String {
|
||||
let inner = cmd
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
rules::CommandArg::Expr(expr) => format!("\"{expr}\""),
|
||||
rules::CommandArg::Command { cmd, .. } => Self::cmd_to_string(cmd),
|
||||
})
|
||||
.join(" ");
|
||||
format!("[{inner}]")
|
||||
}
|
||||
|
||||
/// Returns a function to create a [`Self::GetDefaultJobs`] error from it's inner error.
|
||||
pub fn get_default_jobs() -> impl FnOnce(io::Error) -> Self {
|
||||
move |err| Self::GetDefaultJobs { err }
|
||||
|
||||
@ -4,26 +4,29 @@
|
||||
use {
|
||||
crate::{
|
||||
error::AppError,
|
||||
rules::{AliasOp, Command, DepItem, Exec, Expr, ExprCmpt, OutItem, Rule, Target},
|
||||
rules::{AliasOp, Command, CommandArg, DepItem, Exec, Expr, ExprCmpt, OutItem, Rule, Target},
|
||||
util::CowStr,
|
||||
},
|
||||
itertools::Itertools,
|
||||
std::path::PathBuf,
|
||||
std::{marker::PhantomData, path::PathBuf},
|
||||
};
|
||||
|
||||
/// Expander
|
||||
#[derive(Debug)]
|
||||
pub struct Expander;
|
||||
pub struct Expander<'s> {
|
||||
/// Phantom for `'s`
|
||||
_phantom: PhantomData<&'s ()>,
|
||||
}
|
||||
|
||||
#[expect(clippy::unused_self)] // Currently expander doesn't do anything
|
||||
impl Expander {
|
||||
impl<'s> Expander<'s> {
|
||||
/// Creates a new expander
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
Self { _phantom: PhantomData }
|
||||
}
|
||||
|
||||
/// Expands an expression to it's components
|
||||
pub fn expand_expr<'s>(&self, expr: &Expr<'s>, visitor: &mut impl Visitor<'s>) -> Result<Expr<'s>, AppError> {
|
||||
pub fn expand_expr(&self, expr: &Expr<'s>, visitor: &mut impl Visitor<'s>) -> Result<Expr<'s>, AppError> {
|
||||
// Go through all components
|
||||
let cmpts = expr
|
||||
.cmpts
|
||||
@ -104,11 +107,7 @@ impl Expander {
|
||||
}
|
||||
|
||||
/// Expands an expression into a string
|
||||
pub fn expand_expr_string<'s>(
|
||||
&self,
|
||||
expr: &Expr<'s>,
|
||||
visitor: &mut impl Visitor<'s>,
|
||||
) -> Result<CowStr<'s>, AppError> {
|
||||
pub fn expand_expr_string(&self, expr: &Expr<'s>, visitor: &mut impl Visitor<'s>) -> Result<CowStr<'s>, AppError> {
|
||||
let expr_cmpts = self.expand_expr(expr, visitor)?.cmpts.into_boxed_slice();
|
||||
let res = match Box::<[_; 0]>::try_from(expr_cmpts) {
|
||||
Ok(box []) => Ok("".into()),
|
||||
@ -148,7 +147,7 @@ impl Expander {
|
||||
}
|
||||
|
||||
/// Expands a rule of all it's aliases and patterns
|
||||
pub fn expand_rule<'s>(
|
||||
pub fn expand_rule(
|
||||
&self,
|
||||
rule: &Rule<'s, Expr<'s>>,
|
||||
visitor: &mut impl Visitor<'s>,
|
||||
@ -210,25 +209,11 @@ impl Expander {
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let exec = Exec {
|
||||
cwd: rule
|
||||
.exec
|
||||
.cwd
|
||||
.as_ref()
|
||||
.map(|cwd| self.expand_expr_string(cwd, visitor))
|
||||
.transpose()?,
|
||||
cmds: rule
|
||||
.exec
|
||||
.cmds
|
||||
.iter()
|
||||
.map(|cmd| {
|
||||
Ok(Command {
|
||||
args: cmd
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| self.expand_expr_string(arg, visitor))
|
||||
.collect::<Result<_, _>>()?,
|
||||
})
|
||||
})
|
||||
.map(|cmd| self.expand_cmd(cmd, visitor))
|
||||
.collect::<Result<_, _>>()?,
|
||||
};
|
||||
|
||||
@ -241,8 +226,37 @@ impl Expander {
|
||||
})
|
||||
}
|
||||
|
||||
/// Expands a command
|
||||
pub fn expand_cmd(
|
||||
&self,
|
||||
cmd: &Command<Expr<'s>>,
|
||||
visitor: &mut impl Visitor<'s>,
|
||||
) -> Result<Command<CowStr<'s>>, AppError> {
|
||||
Ok(Command {
|
||||
cwd: cmd
|
||||
.cwd
|
||||
.as_ref()
|
||||
.map(|cwd| self.expand_expr_string(cwd, visitor))
|
||||
.transpose()?,
|
||||
args: cmd
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let arg = match *arg {
|
||||
CommandArg::Expr(ref expr) => CommandArg::Expr(self.expand_expr_string(expr, visitor)?),
|
||||
CommandArg::Command { strip_on_fail, ref cmd } => CommandArg::Command {
|
||||
strip_on_fail,
|
||||
cmd: self.expand_cmd(cmd, visitor)?,
|
||||
},
|
||||
};
|
||||
Ok(arg)
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Expands a target expression
|
||||
pub fn expand_target<'s>(
|
||||
pub fn expand_target(
|
||||
&self,
|
||||
target: &Target<'s, Expr<'s>>,
|
||||
visitor: &mut impl Visitor<'s>,
|
||||
|
||||
138
src/logger.rs
138
src/logger.rs
@ -1,81 +1,121 @@
|
||||
//! Logger
|
||||
|
||||
// TODO: Parse the environment non-lossy first, then use a default.
|
||||
|
||||
// Modules
|
||||
mod pre_init;
|
||||
|
||||
// Imports
|
||||
use {
|
||||
anyhow::Context,
|
||||
std::{
|
||||
env::{self, VarError},
|
||||
fs,
|
||||
io::{self, IsTerminal},
|
||||
path::Path,
|
||||
sync::Mutex,
|
||||
},
|
||||
tracing::metadata::LevelFilter,
|
||||
tracing_subscriber::{prelude::*, EnvFilter},
|
||||
tracing_subscriber::{prelude::*, EnvFilter, Registry},
|
||||
};
|
||||
|
||||
/// Initializes the logger
|
||||
pub fn init(log_file: Option<&Path>) {
|
||||
// Warnings to emit after configuring the logger
|
||||
let mut warnings = vec![];
|
||||
|
||||
///
|
||||
/// Logs to `stderr`, and to `{log_file}`.
|
||||
pub fn init(log_path: Option<&Path>) {
|
||||
// Create the terminal layer
|
||||
let term_use_colors = self::colors_enabled(&mut warnings);
|
||||
let term_layer = tracing_subscriber::fmt::layer().with_ansi(term_use_colors).with_filter(
|
||||
EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy(),
|
||||
);
|
||||
let term_layer = self::term_layer();
|
||||
|
||||
// Create the file layer, if requested
|
||||
let file_layer = log_file.and_then(|log_file| {
|
||||
// Try to create the file
|
||||
let file = match std::fs::File::create(log_file) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
warnings.push(format!("Unable to create log file: {err}"));
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
// Then create the layer
|
||||
let layer = tracing_subscriber::fmt::layer()
|
||||
.with_writer(file)
|
||||
.with_ansi(false)
|
||||
.with_filter(
|
||||
EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::DEBUG.into())
|
||||
.with_env_var("RUST_LOG_FILE")
|
||||
.from_env_lossy(),
|
||||
);
|
||||
|
||||
Some(layer)
|
||||
// Create the file layer
|
||||
let file_layer = log_path.and_then(|log_path| match self::file_layer(log_path) {
|
||||
Ok(layer) => Some(layer),
|
||||
Err(err) => {
|
||||
pre_init::warn(format!("Unable to create file logging layer: {err:?}"));
|
||||
None
|
||||
},
|
||||
});
|
||||
|
||||
// Finally initialize
|
||||
tracing_subscriber::registry().with(term_layer).with(file_layer).init();
|
||||
tracing::debug!(?log_file, ?term_use_colors, "Initialized logging");
|
||||
// Create a registry with all the layers and initialize it
|
||||
Registry::default().with(term_layer).with(file_layer).init();
|
||||
tracing::debug!(?log_path, "Initialized logging");
|
||||
|
||||
// And emit any warnings
|
||||
for warning in warnings {
|
||||
tracing::warn!("{warning}");
|
||||
// And emit all pre-init warnings
|
||||
for message in pre_init::take_traces() {
|
||||
tracing::trace!("{message}");
|
||||
}
|
||||
for message in pre_init::take_debugs() {
|
||||
tracing::debug!("{message}");
|
||||
}
|
||||
for message in pre_init::take_warnings() {
|
||||
tracing::warn!("{message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether to colors should be enabled for the terminal layer.
|
||||
fn colors_enabled(warnings: &mut Vec<String>) -> bool {
|
||||
match env::var("RUST_LOG_COLOR").map(|var| var.to_lowercase()).as_deref() {
|
||||
// By default / `1` / `yes` / `true`, use colors
|
||||
Err(VarError::NotPresent) | Ok("1" | "yes" | "true") => true,
|
||||
/// Creates the terminal layer
|
||||
fn term_layer<S>() -> impl tracing_subscriber::Layer<S>
|
||||
where
|
||||
S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + 'static,
|
||||
{
|
||||
let enable_colors = self::term_enable_colors();
|
||||
pre_init::debug(format!("Stderr logging colors: {enable_colors}"));
|
||||
|
||||
// On `0`, `no`, `false`, don't
|
||||
let env = env::var("RUST_LOG").unwrap_or_else(|_| "info".to_owned());
|
||||
pre_init::debug(format!("Stderr logging filter: {env}"));
|
||||
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_ansi(enable_colors)
|
||||
.with_writer(io::stderr)
|
||||
.with_filter(
|
||||
EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.parse_lossy(env),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates the file layer
|
||||
fn file_layer<S>(log_path: &Path) -> Result<impl tracing_subscriber::Layer<S>, anyhow::Error>
|
||||
where
|
||||
S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + 'static,
|
||||
{
|
||||
// Parse the environment
|
||||
let env = env::var("RUST_FILE_LOG").unwrap_or_else(|_| "debug".to_owned());
|
||||
pre_init::debug(format!("File logging filter: {env}"));
|
||||
|
||||
// Try to create the log file parent, if it doesn't exist.
|
||||
let parent_dir = log_path.parent().context("Log path has no parent directory")?;
|
||||
fs::create_dir_all(parent_dir).context("Unable to create log path parent directory")?;
|
||||
|
||||
// Then create the file
|
||||
let file = fs::File::create(log_path).context("Unable to create log file")?;
|
||||
|
||||
// And finally the layer
|
||||
let layer = tracing_subscriber::fmt::layer()
|
||||
.with_writer(Mutex::new(file))
|
||||
.with_ansi(false)
|
||||
.with_filter(EnvFilter::builder().parse_lossy(env));
|
||||
|
||||
Ok(layer)
|
||||
}
|
||||
|
||||
/// Returns whether to colors should be enabled for the terminal layer.
|
||||
fn term_enable_colors() -> bool {
|
||||
match env::var("RUST_LOG_COLOR").map(|var| var.to_lowercase()).as_deref() {
|
||||
// If it isn't present, check if we're in a terminal
|
||||
Err(VarError::NotPresent) => io::stderr().is_terminal(),
|
||||
|
||||
// Else check user input
|
||||
Ok("1" | "yes" | "true") => true,
|
||||
Ok("0" | "no" | "false") => false,
|
||||
|
||||
// Else don't use colors, but warn
|
||||
// On invalid input, warn and don't use colors
|
||||
Ok(env) => {
|
||||
warnings.push(format!(
|
||||
pre_init::warn(format!(
|
||||
"Ignoring unknown `RUST_LOG_COLOR` value: {env:?}, expected `0`, `1`, `yes`, `no`, `true`, `false`"
|
||||
));
|
||||
false
|
||||
},
|
||||
Err(VarError::NotUnicode(err)) => {
|
||||
warnings.push(format!("Ignoring non-utf8 `RUST_LOG_COLOR`: {err:?}"));
|
||||
pre_init::warn(format!("Ignoring non-utf8 `RUST_LOG_COLOR`: {err:?}"));
|
||||
false
|
||||
},
|
||||
}
|
||||
|
||||
48
src/logger/pre_init.rs
Normal file
48
src/logger/pre_init.rs
Normal file
@ -0,0 +1,48 @@
|
||||
//! Pre-initialization
|
||||
|
||||
// TODO: Use a proper solution that initializes a temporary subscriber and keeps all the records and events.
|
||||
|
||||
// Imports
|
||||
use std::sync::{
|
||||
atomic::{self, AtomicBool},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
/// If logging as already initialized
|
||||
static IS_INIT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Creates the pre-init functions for a level
|
||||
macro pre_init_fns(
|
||||
$(
|
||||
$NAME:ident, $log:ident, $take:ident;
|
||||
)*
|
||||
) {
|
||||
$(
|
||||
static $NAME: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
|
||||
/// Emits a log
|
||||
#[allow(dead_code)]
|
||||
pub fn $log(message: impl Into<String>) {
|
||||
let message = message.into();
|
||||
match IS_INIT.load(atomic::Ordering::Acquire) {
|
||||
true => {
|
||||
tracing::warn!(?message, "Using pre-initialization logging after initialization");
|
||||
tracing::$log!("{message}")
|
||||
},
|
||||
false => $NAME.lock().expect("Poisoned").push(message),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves all logs
|
||||
pub(super) fn $take() -> Vec<String> {
|
||||
IS_INIT.store(true, atomic::Ordering::Release);
|
||||
$NAME.lock().expect("Poisoned").drain(..).collect()
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
pre_init_fns! {
|
||||
TRACES , trace, take_traces ;
|
||||
DEBUGS , debug, take_debugs ;
|
||||
WARNINGS, warn , take_warnings;
|
||||
}
|
||||
30
src/main.rs
30
src/main.rs
@ -11,8 +11,11 @@
|
||||
async_fn_in_trait,
|
||||
yeet_expr,
|
||||
must_not_suspend,
|
||||
strict_provenance
|
||||
strict_provenance,
|
||||
assert_matches
|
||||
)]
|
||||
// Lints
|
||||
#![allow(clippy::print_stdout, reason = "We're a binary that should talk to the user")]
|
||||
|
||||
// Modules
|
||||
mod args;
|
||||
@ -35,8 +38,10 @@ use {
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
env,
|
||||
fmt,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
thread,
|
||||
time::{Duration, SystemTime},
|
||||
},
|
||||
util::CowStr,
|
||||
@ -66,10 +71,10 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
let zbuild_path = zbuild_path.file_name().expect("Zbuild path had no file name");
|
||||
let zbuild_path = Path::new(zbuild_path);
|
||||
tracing::debug!(?zbuild_dir, "Moving to zbuild directory");
|
||||
std::env::set_current_dir(zbuild_dir).map_err(AppError::set_current_dir(zbuild_dir))?;
|
||||
env::set_current_dir(zbuild_dir).map_err(AppError::set_current_dir(zbuild_dir))?;
|
||||
|
||||
// Parse the ast
|
||||
let zbuild_file = fs::read_to_string(&zbuild_path).map_err(AppError::read_file(&zbuild_path))?;
|
||||
let zbuild_file = fs::read_to_string(zbuild_path).map_err(AppError::read_file(&zbuild_path))?;
|
||||
tracing::trace!(?zbuild_file, "Read zbuild.yaml");
|
||||
let ast = serde_yaml::from_str::<Ast<'_>>(&zbuild_file).map_err(AppError::parse_yaml(&zbuild_path))?;
|
||||
tracing::trace!(?ast, "Parsed ast");
|
||||
@ -85,7 +90,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
1
|
||||
},
|
||||
Some(jobs) => jobs,
|
||||
None => std::thread::available_parallelism()
|
||||
None => thread::available_parallelism()
|
||||
.map_err(AppError::get_default_jobs())?
|
||||
.into(),
|
||||
};
|
||||
@ -115,7 +120,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
// If there was a rule, use it without any patterns
|
||||
// TODO: If it requires patterns maybe error out here?
|
||||
|rule| rules::Target::Rule {
|
||||
rule: rules::Expr::string(rule.name.to_string()),
|
||||
rule: rules::Expr::string(rule.name.to_owned()),
|
||||
pats: HashMap::new(),
|
||||
},
|
||||
)
|
||||
@ -131,11 +136,11 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
let watcher = args
|
||||
.watch
|
||||
.then(|| {
|
||||
Watcher::new(
|
||||
builder.subscribe_events(),
|
||||
// TODO: Better default?
|
||||
args.watch_debouncer_timeout_ms.unwrap_or(0.0),
|
||||
)
|
||||
// TODO: Better default?
|
||||
let debouncer_timeout_ms = args.watcher_debouncer_timeout_ms.unwrap_or(0.0);
|
||||
let debouncer_timeout = { Duration::from_secs_f64(debouncer_timeout_ms / 1000.0) };
|
||||
|
||||
Watcher::new(builder.subscribe_events(), debouncer_timeout)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
@ -188,8 +193,7 @@ async fn find_zbuild() -> Result<PathBuf, AppError> {
|
||||
}
|
||||
|
||||
/// Builds a target.
|
||||
#[expect(clippy::future_not_send)] // Auto-traits are propagated (TODO: Maybe? Check if this is true)
|
||||
async fn build_target<'s, T: BuildableTargetInner<'s> + std::fmt::Display + std::fmt::Debug>(
|
||||
async fn build_target<'s, T: BuildableTargetInner<'s> + fmt::Display + fmt::Debug>(
|
||||
builder: &Builder<'s>,
|
||||
target: &rules::Target<'s, T>,
|
||||
rules: &Rules<'s>,
|
||||
@ -213,7 +217,7 @@ async fn build_target<'s, T: BuildableTargetInner<'s> + std::fmt::Display + std:
|
||||
println!("{target}");
|
||||
};
|
||||
},
|
||||
Err(err) => tracing::error!(?target, err=?anyhow::Error::new(err), "Unable to build target"),
|
||||
Err(err) => tracing::error!(%target, err=?anyhow::Error::new(err), "Unable to build target"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ pub use {
|
||||
expr::{Expr, ExprCmpt},
|
||||
item::{DepItem, OutItem},
|
||||
pattern::{Pattern, PatternOp},
|
||||
rule::{Command, Exec, Rule},
|
||||
rule::{Command, CommandArg, Exec, Rule},
|
||||
target::Target,
|
||||
};
|
||||
|
||||
|
||||
@ -36,26 +36,7 @@ impl<'s> Rule<'s, Expr<'s>> {
|
||||
.collect();
|
||||
let output = rule.out.into_iter().map(OutItem::new).collect();
|
||||
let deps = rule.deps.into_iter().map(DepItem::new).collect();
|
||||
let exec = match rule.exec {
|
||||
ast::Exec::OnlyCmds(cmds) => Exec {
|
||||
cwd: None,
|
||||
cmds: cmds
|
||||
.into_iter()
|
||||
.map(|cmd| Command {
|
||||
args: cmd.args.into_iter().map(Expr::new).collect(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
ast::Exec::Full { cwd, cmds } => Exec {
|
||||
cwd: cwd.map(Expr::new),
|
||||
cmds: cmds
|
||||
.into_iter()
|
||||
.map(|cmd| Command {
|
||||
args: cmd.args.into_iter().map(Expr::new).collect(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
};
|
||||
let exec = Exec::new(rule.exec);
|
||||
|
||||
Self {
|
||||
name,
|
||||
@ -71,17 +52,79 @@ impl<'s> Rule<'s, Expr<'s>> {
|
||||
/// Exec
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Exec<T> {
|
||||
/// Working directory
|
||||
pub cwd: Option<T>,
|
||||
|
||||
/// Commands
|
||||
pub cmds: Vec<Command<T>>,
|
||||
}
|
||||
|
||||
impl<'s> Exec<Expr<'s>> {
|
||||
/// Creates a new exec from it's ast
|
||||
pub fn new(exec: ast::Exec<'s>) -> Self {
|
||||
Self {
|
||||
cmds: exec.cmds.into_iter().map(Command::new).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Command
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Command<T> {
|
||||
/// Working directory
|
||||
pub cwd: Option<T>,
|
||||
|
||||
/// All arguments
|
||||
pub args: Vec<T>,
|
||||
pub args: Vec<CommandArg<T>>,
|
||||
}
|
||||
|
||||
impl<'s> Command<Expr<'s>> {
|
||||
/// Creates a new command from it's ast
|
||||
pub fn new(cmd: ast::Command<'s>) -> Self {
|
||||
match cmd {
|
||||
ast::Command::OnlyArgs(args) => Self {
|
||||
cwd: None,
|
||||
args: args.into_iter().map(CommandArg::new).collect(),
|
||||
},
|
||||
ast::Command::Full { cwd, args } => Self {
|
||||
cwd: cwd.map(Expr::new),
|
||||
args: args.into_iter().map(CommandArg::new).collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Command argument
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CommandArg<T> {
|
||||
/// Expression
|
||||
Expr(T),
|
||||
|
||||
/// Command
|
||||
Command {
|
||||
/// Strip the command if failed
|
||||
strip_on_fail: bool,
|
||||
|
||||
/// Command
|
||||
cmd: Command<T>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'s> CommandArg<Expr<'s>> {
|
||||
/// Creates a new command argument from it's ast
|
||||
pub fn new(arg: ast::CommandArg<'s>) -> Self {
|
||||
match arg {
|
||||
ast::CommandArg::Expr(expr) => Self::Expr(Expr::new(expr)),
|
||||
ast::CommandArg::Command(cmd) => Self::Command {
|
||||
strip_on_fail: false,
|
||||
cmd: Command::new(cmd),
|
||||
},
|
||||
ast::CommandArg::CommandFull { strip_on_fail, cmd } => Self::Command {
|
||||
strip_on_fail,
|
||||
cmd: Command::new(cmd),
|
||||
},
|
||||
ast::CommandArg::StripOnFail { cmd } => Self::Command {
|
||||
strip_on_fail: true,
|
||||
cmd: Command::new(cmd),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ use {
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
},
|
||||
};
|
||||
|
||||
@ -62,7 +63,7 @@ impl<'s> Target<'s, Expr<'s>> {
|
||||
|
||||
impl<T: Hash + Ord> Hash for Target<'_, T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
core::mem::discriminant(self).hash(state);
|
||||
mem::discriminant(self).hash(state);
|
||||
match self {
|
||||
Self::File { file, is_static } => {
|
||||
file.hash(state);
|
||||
|
||||
13
src/util.rs
13
src/util.rs
@ -7,7 +7,8 @@ use {
|
||||
pin_project::pin_project,
|
||||
std::{
|
||||
borrow::Cow,
|
||||
path::Path,
|
||||
io,
|
||||
path::{self, Path},
|
||||
pin::Pin,
|
||||
task,
|
||||
time::{Duration, Instant},
|
||||
@ -30,17 +31,17 @@ pub macro chain {
|
||||
}
|
||||
|
||||
/// Async `std::fs_try_exists`
|
||||
pub async fn fs_try_exists(path: impl AsRef<Path> + Send) -> Result<bool, std::io::Error> {
|
||||
pub async fn fs_try_exists(path: impl AsRef<Path> + Send) -> Result<bool, io::Error> {
|
||||
match fs::metadata(path).await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(false),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Measures the duration of a fallible future
|
||||
#[expect(clippy::future_not_send)] // It is send if `F: Send` (TODO: Check if this is true)
|
||||
pub async fn try_measure_async<F: Future<Output = Result<T, E>>, T, E>(fut: F) -> Result<(Duration, T), E> {
|
||||
/// Wrapper future for measuring the future
|
||||
#[pin_project]
|
||||
struct Wrapper<F> {
|
||||
/// Future
|
||||
@ -71,7 +72,7 @@ pub async fn try_measure_async<F: Future<Output = Result<T, E>>, T, E>(fut: F) -
|
||||
|
||||
/// Normalizes a string path
|
||||
pub fn normalize_path(path: &str) -> String {
|
||||
let ends_with_sep = path.ends_with(std::path::MAIN_SEPARATOR_STR);
|
||||
let ends_with_sep = path.ends_with(path::MAIN_SEPARATOR_STR);
|
||||
|
||||
let mut path = Path::new(&path)
|
||||
.normalized()
|
||||
@ -82,7 +83,7 @@ pub fn normalize_path(path: &str) -> String {
|
||||
// Note: `npath` doesn't keep `/` at the end, so we have to do it manually
|
||||
match ends_with_sep {
|
||||
true => {
|
||||
path.push_str(std::path::MAIN_SEPARATOR_STR);
|
||||
path.push_str(path::MAIN_SEPARATOR_STR);
|
||||
path
|
||||
},
|
||||
false => path,
|
||||
|
||||
@ -15,10 +15,12 @@ use {
|
||||
notify::Watcher as _,
|
||||
notify_debouncer_full::Debouncer,
|
||||
std::{
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
},
|
||||
tokio::sync::mpsc,
|
||||
tokio_stream::wrappers::ReceiverStream,
|
||||
};
|
||||
|
||||
@ -51,26 +53,24 @@ impl<'s> Watcher<'s> {
|
||||
/// Creates a new watcher
|
||||
pub fn new(
|
||||
builder_event_rx: async_broadcast::Receiver<build::Event<'s>>,
|
||||
watch_debouncer_timeout_ms: f64,
|
||||
debouncer_timeout: Duration,
|
||||
) -> Result<Self, AppError> {
|
||||
// Create the watcher
|
||||
let (fs_event_tx, fs_event_rx) = tokio::sync::mpsc::channel(16);
|
||||
let watcher = notify_debouncer_full::new_debouncer(
|
||||
Duration::from_secs_f64(watch_debouncer_timeout_ms / 1000.0),
|
||||
None,
|
||||
move |fs_events| match fs_events {
|
||||
Ok(fs_events) =>
|
||||
for fs_event in fs_events {
|
||||
tracing::trace!(?fs_event, "Watcher fs event");
|
||||
#[expect(let_underscore_drop)] // We don't care if it succeeded or not
|
||||
let _ = fs_event_tx.blocking_send(fs_event);
|
||||
},
|
||||
Err(errs) =>
|
||||
for err in errs {
|
||||
tracing::warn!(err=?anyhow::Error::from(err), "Error while watching");
|
||||
},
|
||||
},
|
||||
)
|
||||
let (fs_event_tx, fs_event_rx) = mpsc::channel(16);
|
||||
let watcher = notify_debouncer_full::new_debouncer(debouncer_timeout, None, move |fs_events| match fs_events {
|
||||
Ok(fs_events) =>
|
||||
for fs_event in fs_events {
|
||||
tracing::trace!(?fs_event, "Watcher fs event");
|
||||
|
||||
// Note: We don't care if it succeeded or not
|
||||
#[expect(let_underscore_drop, clippy::let_underscore_must_use)]
|
||||
let _: Result<(), _> = fs_event_tx.blocking_send(fs_event);
|
||||
},
|
||||
Err(errs) =>
|
||||
for err in errs {
|
||||
tracing::warn!(err=?anyhow::Error::from(err), "Error while watching");
|
||||
},
|
||||
})
|
||||
.context("Unable to create file watcher")
|
||||
.map_err(AppError::Other)?;
|
||||
|
||||
@ -122,14 +122,16 @@ impl<'s> Watcher<'s> {
|
||||
// until the root, and by that point we'd just be watching
|
||||
// all filesystem changes...
|
||||
tracing::trace!(?dep_path, "Starting to watch path");
|
||||
if let Err(err) = self.watcher.watcher().watch(
|
||||
&dep_path.parent().unwrap_or(&dep_path),
|
||||
notify::RecursiveMode::Recursive,
|
||||
) {
|
||||
tracing::warn!(?dep_path, ?err, "Unable to watch path")
|
||||
if let Err(err) = self
|
||||
.watcher
|
||||
.watcher()
|
||||
.watch(dep_path.parent().unwrap_or(&dep_path), notify::RecursiveMode::Recursive)
|
||||
{
|
||||
tracing::warn!(?dep_path, ?err, "Unable to watch path");
|
||||
}
|
||||
|
||||
rev_deps
|
||||
// Note: We don't care if we add a duplicate target
|
||||
let _: bool = rev_deps
|
||||
.entry(dep_path)
|
||||
.or_insert_with(|| RevDep {
|
||||
target: dep,
|
||||
@ -153,7 +155,7 @@ impl<'s> Watcher<'s> {
|
||||
Err(err) => {
|
||||
// TODO: Warn on all occasions once this code path isn't hit
|
||||
// by random files that aren't actually dependencies.
|
||||
if err.kind() != std::io::ErrorKind::NotFound {
|
||||
if err.kind() != io::ErrorKind::NotFound {
|
||||
tracing::warn!(?path, ?err, "Unable to canonicalize");
|
||||
}
|
||||
return;
|
||||
@ -182,7 +184,7 @@ impl<'s> Watcher<'s> {
|
||||
builder
|
||||
.reset_build(&rev_dep.target, rules)
|
||||
.await
|
||||
.expect("Unable to reset existing build")
|
||||
.expect("Unable to reset existing build");
|
||||
},
|
||||
dep_parents
|
||||
.iter()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user