diff --git a/Cargo.lock b/Cargo.lock index f2b643c..81a43f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -17,20 +17,11 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" -version = "0.6.21" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -43,9 +34,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" @@ -58,22 +49,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.11" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -90,15 +81,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "bumpalo" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "cassowary" @@ -115,40 +100,17 @@ dependencies = [ "rustversion", ] -[[package]] -name = "cc" -version = "1.2.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chrono" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "clap" -version = "4.5.57" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -156,9 +118,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.57" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -168,9 +130,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -180,9 +142,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.7" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cognos" @@ -215,19 +177,13 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.10.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" dependencies = [ "unicode-segmentation", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "crossterm" version = "0.28.1" @@ -256,7 +212,7 @@ dependencies = [ "document-features", "mio", "parking_lot", - "rustix 1.1.3", + "rustix 1.0.8", "signal-hook", "signal-hook-mio", "winapi", @@ -285,18 +241,18 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] [[package]] name = "darling" -version = "0.23.0" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -304,10 +260,11 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ + "fnv", "ident_case", "proc-macro2", "quote", @@ -317,9 +274,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", @@ -328,31 +285,30 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.1.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", "syn", ] [[package]] name = "document-features" -version = "0.2.12" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -371,12 +327,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.14" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -396,10 +352,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" @@ -409,14 +365,14 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", - "wasip2", + "wasi 0.14.3+wasi-0.2.4", ] [[package]] @@ -432,9 +388,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -442,30 +398,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -480,30 +412,27 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.16.0", "serde", "serde_core", ] [[package]] name = "indoc" -version = "2.0.7" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" [[package]] name = "instability" -version = "0.3.11" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d" +checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" dependencies = [ "darling", "indoc", @@ -514,9 +443,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -529,19 +458,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "js-sys" -version = "0.3.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" -dependencies = [ - "once_cell", - "wasm-bindgen", -] +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "lazy_static" @@ -551,9 +470,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "linux-raw-sys" @@ -563,30 +482,31 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litrs" -version = "1.0.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" -version = "0.4.14" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.29" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lru" @@ -608,38 +528,29 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "mio" -version = "1.1.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi", - "windows-sys 0.61.2", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "nu-ansi-term" -version = "0.50.3" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", + "windows-sys 0.52.0", ] [[package]] @@ -650,15 +561,15 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "parking_lot" -version = "0.12.5" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -666,15 +577,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.12" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -691,18 +602,18 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -736,18 +647,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.18" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags", ] [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -756,16 +667,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rom" version = "0.1.0" dependencies = [ "anyhow", - "chrono", "clap", "cognos", "crossterm 0.29.0", @@ -781,15 +691,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.44" @@ -805,15 +706,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "linux-raw-sys 0.9.4", + "windows-sys 0.60.2", ] [[package]] @@ -824,9 +725,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -834,12 +735,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -872,15 +767,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", + "ryu", "serde", "serde_core", - "zmij", ] [[package]] @@ -903,12 +798,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook" version = "0.3.18" @@ -921,9 +810,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -932,11 +821,10 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.8" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ - "errno", "libc", ] @@ -982,9 +870,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -993,31 +881,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.24.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom", "once_cell", - "rustix 1.1.3", - "windows-sys 0.61.2", + "rustix 1.0.8", + "windows-sys 0.60.2", ] [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -1035,9 +923,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.44" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1046,9 +934,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.31" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -1057,9 +945,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.36" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -1078,9 +966,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", @@ -1096,9 +984,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -1148,59 +1036,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" +name = "wasi" +version = "0.14.3+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" -dependencies = [ - "unicode-ident", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1223,63 +1066,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-link" -version = "0.2.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] -name = "windows-result" -version = "0.4.1" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -1288,16 +1087,16 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.61.2" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-link", + "windows-targets 0.53.3", ] [[package]] @@ -1306,14 +1105,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -1322,42 +1138,84 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1365,13 +1223,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "wit-bindgen" -version = "0.51.0" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] -name = "zmij" -version = "1.0.19" +name = "wit-bindgen" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" diff --git a/Cargo.toml b/Cargo.toml index 5456e9a..00288d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ version = "0.1.0" edition = "2024" authors = ["NotAShelf "] description = "Pretty build graphs for Nix builds" -rust-version = "1.91.1" +rust-version = "1.85" [workspace.dependencies] anyhow = "1.0.100" @@ -19,7 +19,6 @@ crossterm = "0.29.0" ratatui = "0.29.0" indexmap = { version = "2.12.0", features = ["serde"] } csv = "1.4.0" -chrono = "0.4.42" thiserror = "2.0.17" tracing = "0.1.41" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/flake.lock b/flake.lock index c2a8a2c..8a30674 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1770115704, - "narHash": "sha256-KHFT9UWOF2yRPlAnSXQJh6uVcgNcWlFqqiAZ7OVlHNc=", + "lastModified": 1765186076, + "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e6eae2ee2110f3d31110d5c222cd395303343b08", + "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8", "type": "github" }, "original": { diff --git a/rom/Cargo.toml b/rom/Cargo.toml index 6affa5b..979e965 100644 --- a/rom/Cargo.toml +++ b/rom/Cargo.toml @@ -19,7 +19,6 @@ crossterm = "0.29" ratatui = "0.29" indexmap.workspace = true csv.workspace = true -chrono.workspace = true thiserror.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/rom/src/cache.rs b/rom/src/cache.rs deleted file mode 100644 index b3c9dbf..0000000 --- a/rom/src/cache.rs +++ /dev/null @@ -1,397 +0,0 @@ - -use std::{ - collections::HashMap, - fs::{self, File, OpenOptions}, - io::{BufReader, BufWriter}, - path::PathBuf, - time::SystemTime, -}; - -use csv::{Reader, Writer}; -use serde::{Deserialize, Serialize}; - -use crate::state::BuildReport; - -/// Maximum number of historical builds to keep per derivation -const HISTORY_LIMIT: usize = 10; - -/// Build report cache for CSV persistence -pub struct BuildReportCache { - cache_path: PathBuf, -} - -/// CSV row format for build reports -#[derive(Debug, Clone, Serialize, Deserialize)] -struct BuildReportRow { - hostname: String, - derivation_name: String, - utc_time: String, - build_seconds: u64, -} - -impl BuildReportCache { - /// Create a new cache instance with the given path - #[must_use] - pub fn new(cache_path: PathBuf) -> Self { - Self { cache_path } - } - - // FIXME: just use the dirs crate for this - /// Get the default cache directory path - /// - /// Uses `$XDG_STATE_HOME` if set, otherwise ``~/.local/state` - #[must_use] - pub fn default_cache_dir() -> PathBuf { - if let Ok(xdg_state) = std::env::var("XDG_STATE_HOME") { - PathBuf::from(xdg_state).join("rom") - } else if let Ok(home) = std::env::var("HOME") { - PathBuf::from(home).join(".local/state/rom") - } else { - PathBuf::from(".rom") - } - } - - /// Get the default cache file path - #[must_use] - pub fn default_cache_path() -> PathBuf { - Self::default_cache_dir().join("build-reports.csv") - } - - /// Load build reports from CSV - /// - /// Returns empty [`HashMap`] if file doesn't exist or parsing fails - pub fn load(&self) -> HashMap<(String, String), Vec> { - if !self.cache_path.exists() { - return HashMap::new(); - } - - let file = match File::open(&self.cache_path) { - Ok(f) => f, - Err(_) => return HashMap::new(), - }; - - let reader = BufReader::new(file); - let mut csv_reader = Reader::from_reader(reader); - - let mut reports: HashMap<(String, String), Vec> = - HashMap::new(); - - for result in csv_reader.deserialize() { - let row: BuildReportRow = match result { - Ok(r) => r, - Err(_) => continue, - }; - - let completed_at = match parse_utc_time(&row.utc_time) { - Some(t) => t, - None => continue, - }; - - let report = BuildReport { - derivation_name: row.derivation_name.clone(), - platform: String::new(), // FIXME: not stored in CSV, for simplicity and because I'm lazy - duration_secs: row.build_seconds as f64, - completed_at, - host: row.hostname.clone(), - success: true, // only successful builds are cached - }; - - let key = (row.hostname, row.derivation_name); - reports.entry(key).or_default().push(report); - } - - // Sort each entry by timestamp (newest first) and limit to HISTORY_LIMIT - for entries in reports.values_mut() { - entries.sort_by(|a, b| b.completed_at.cmp(&a.completed_at)); - entries.truncate(HISTORY_LIMIT); - } - - reports - } - - /// Save build reports to CSV - /// - /// Merges with existing reports and enforces history limit - pub fn save( - &self, - reports: &HashMap<(String, String), Vec>, - ) -> Result<(), std::io::Error> { - // Ensure directory exists - if let Some(parent) = self.cache_path.parent() { - fs::create_dir_all(parent)?; - } - - // Load existing reports to merge - let mut merged = self.load(); - - // Merge new reports - for ((host, drv_name), new_reports) in reports { - let key = (host.clone(), drv_name.clone()); - let existing = merged.entry(key).or_default(); - - // Add new reports - existing.extend(new_reports.iter().cloned()); - - // Sort by timestamp (newest first) - existing.sort_by(|a, b| b.completed_at.cmp(&a.completed_at)); - - // Keep only most recent HISTORY_LIMIT entries - existing.truncate(HISTORY_LIMIT); - } - - // Write to CSV - let file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(&self.cache_path)?; - - let writer = BufWriter::new(file); - let mut csv_writer = Writer::from_writer(writer); - - // Flatten and write all reports - for ((hostname, derivation_name), entries) in merged { - for report in entries { - let row = BuildReportRow { - hostname: hostname.clone(), - derivation_name: derivation_name.clone(), - utc_time: format_utc_time(report.completed_at), - build_seconds: report.duration_secs as u64, - }; - csv_writer.serialize(row)?; - } - } - - csv_writer.flush()?; - Ok(()) - } - - /// Calculate median build time from historical reports - /// - /// Returns [`None`] if there are no reports - #[must_use] - pub fn calculate_median(reports: &[BuildReport]) -> Option { - if reports.is_empty() { - return None; - } - - let mut durations: Vec = - reports.iter().map(|r| r.duration_secs as u64).collect(); - durations.sort_unstable(); - - let len = durations.len(); - if len % 2 == 1 { - Some(durations[len / 2]) - } else { - let mid1 = durations[len / 2 - 1]; - let mid2 = durations[len / 2]; - Some((mid1 + mid2) / 2) - } - } - - /// Get median build time for a specific derivation on a host - #[must_use] - pub fn get_estimate( - &self, - reports: &HashMap<(String, String), Vec>, - host: &str, - derivation_name: &str, - ) -> Option { - let key = (host.to_string(), derivation_name.to_string()); - let entries = reports.get(&key)?; - Self::calculate_median(entries) - } -} - -/// Parse UTC time string in format "%Y-%m-%d %H:%M:%S" -fn parse_utc_time(s: &str) -> Option { - // Simple parsing for "YYYY-MM-DD HH:MM:SS" format - let parts: Vec<&str> = s.split([' ', '-', ':']).collect(); - if parts.len() != 6 { - return None; - } - - let year: i64 = parts[0].parse().ok()?; - let month: u64 = parts[1].parse().ok()?; - let day: u64 = parts[2].parse().ok()?; - let hour: u64 = parts[3].parse().ok()?; - let minute: u64 = parts[4].parse().ok()?; - let second: u64 = parts[5].parse().ok()?; - - // Approximate conversion to Unix timestamp - // This is a simplified calculation that doesn't handle leap years perfectly - let days_since_epoch = (year - 1970) * 365 - + (year - 1969) / 4 - + days_until_month(month) - + day as i64 - - 1; - let seconds_since_epoch = - days_since_epoch as u64 * 86400 + hour * 3600 + minute * 60 + second; - - Some( - SystemTime::UNIX_EPOCH - + std::time::Duration::from_secs(seconds_since_epoch), - ) -} - -// FIXME: I'm really sure there's a library for this but lets just get -// this thing compiling -/// Calculate days until the start of a month (approximation) -const fn days_until_month(month: u64) -> i64 { - match month { - 1 => 0, - 2 => 31, - 3 => 59, - 4 => 90, - 5 => 120, - 6 => 151, - 7 => 181, - 8 => 212, - 9 => 243, - 10 => 273, - 11 => 304, - 12 => 334, - _ => 0, - } -} - -// FIXME: does Chrono do this? -/// Format SystemTime as UTC string in format "%Y-%m-%d %H:%M:%S" -fn format_utc_time(time: SystemTime) -> String { - let duration = time - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_default(); - let secs = duration.as_secs(); - - let days = secs / 86400; - let remaining = secs % 86400; - let hours = remaining / 3600; - let minutes = (remaining % 3600) / 60; - let seconds = remaining % 60; - - // Approximate conversion from days since epoch to date - let mut year = 1970; - let mut days_left = days as i64; - - // Subtract full years - while days_left >= 365 { - if is_leap_year(year) && days_left >= 366 { - days_left -= 366; - year += 1; - } else if !is_leap_year(year) { - days_left -= 365; - year += 1; - } else { - break; - } - } - - // Calculate month and day - let (month, day) = calculate_month_day(days_left as u64, is_leap_year(year)); - - format!("{year:04}-{month:02}-{day:02} {hours:02}:{minutes:02}:{seconds:02}") -} - -const fn is_leap_year(year: i64) -> bool { - (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) -} - -fn calculate_month_day(days: u64, is_leap: bool) -> (u8, u8) { - let days_in_month: [u8; 12] = if is_leap { - [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - } else { - [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - }; - - let mut remaining = days as i32; - for (i, &month_days) in days_in_month.iter().enumerate() { - if remaining < i32::from(month_days) { - return ((i + 1) as u8, (remaining + 1) as u8); - } - remaining -= i32::from(month_days); - } - - (12, 31) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_calculate_median_odd() { - let reports = vec![ - BuildReport { - derivation_name: "test".to_string(), - platform: "x86_64-linux".to_string(), - duration_secs: 10.0, - completed_at: SystemTime::UNIX_EPOCH, - host: "localhost".to_string(), - success: true, - }, - BuildReport { - derivation_name: "test".to_string(), - platform: "x86_64-linux".to_string(), - duration_secs: 20.0, - completed_at: SystemTime::UNIX_EPOCH, - host: "localhost".to_string(), - success: true, - }, - BuildReport { - derivation_name: "test".to_string(), - platform: "x86_64-linux".to_string(), - duration_secs: 30.0, - completed_at: SystemTime::UNIX_EPOCH, - host: "localhost".to_string(), - success: true, - }, - ]; - - assert_eq!(BuildReportCache::calculate_median(&reports), Some(20)); - } - - #[test] - fn test_calculate_median_even() { - let reports = vec![ - BuildReport { - derivation_name: "test".to_string(), - platform: "x86_64-linux".to_string(), - duration_secs: 10.0, - completed_at: SystemTime::UNIX_EPOCH, - host: "localhost".to_string(), - success: true, - }, - BuildReport { - derivation_name: "test".to_string(), - platform: "x86_64-linux".to_string(), - duration_secs: 20.0, - completed_at: SystemTime::UNIX_EPOCH, - host: "localhost".to_string(), - success: true, - }, - ]; - - assert_eq!(BuildReportCache::calculate_median(&reports), Some(15)); - } - - #[test] - fn test_calculate_median_empty() { - let reports = vec![]; - assert_eq!(BuildReportCache::calculate_median(&reports), None); - } - - #[test] - fn test_format_parse_utc_time() { - let time = - SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000); - let formatted = format_utc_time(time); - let parsed = parse_utc_time(&formatted).unwrap(); - - // Allow small difference due to approximation - let diff = parsed - .duration_since(time) - .unwrap_or_else(|e| e.duration()) - .as_secs(); - assert!(diff < 86400); // less than 1 day difference - } -} diff --git a/rom/src/cli.rs b/rom/src/cli.rs index e6508e7..98ecaef 100644 --- a/rom/src/cli.rs +++ b/rom/src/cli.rs @@ -33,14 +33,6 @@ pub struct Cli { /// Summary display style: concise, table, full #[arg(long, global = true, default_value = "concise")] pub summary: String, - - /// Log prefix style: short, full, none - #[arg(long, global = true, default_value = "short")] - pub log_prefix: String, - - /// Maximum number of log lines to display - #[arg(long, global = true)] - pub log_lines: Option, } #[derive(Debug, clap::Subcommand)] @@ -94,8 +86,6 @@ pub fn run() -> eyre::Result<()> { cli.format.clone(), cli.legend.clone(), cli.summary.clone(), - cli.log_prefix.clone(), - cli.log_lines, )?; Ok(()) }, @@ -111,8 +101,6 @@ pub fn run() -> eyre::Result<()> { cli.format.clone(), cli.legend.clone(), cli.summary.clone(), - cli.log_prefix.clone(), - cli.log_lines, )?; Ok(()) }, @@ -122,18 +110,14 @@ pub fn run() -> eyre::Result<()> { // If no args provided and --json is set, use piping mode from stdin if args.is_empty() && cli.json { let config = crate::types::Config { - piping: false, - silent: cli.silent, - input_mode: crate::types::InputMode::Json, - show_timers: true, - width: None, - format: crate::types::DisplayFormat::from_str(&cli.format), - legend_style: cli.legend.clone(), - summary_style: cli.summary.clone(), - log_prefix_style: crate::types::LogPrefixStyle::from_str( - &cli.log_prefix, - ), - log_line_limit: cli.log_lines, + piping: false, + silent: cli.silent, + input_mode: crate::types::InputMode::Json, + show_timers: true, + width: None, + format: crate::types::DisplayFormat::from_str(&cli.format), + legend_style: cli.legend.clone(), + summary_style: cli.summary.clone(), }; let stdin = io::stdin(); @@ -156,8 +140,6 @@ pub fn run() -> eyre::Result<()> { cli.format.clone(), cli.legend.clone(), cli.summary.clone(), - cli.log_prefix.clone(), - cli.log_lines, )?; Ok(()) }, @@ -167,18 +149,14 @@ pub fn run() -> eyre::Result<()> { // If no args provided and --json is set, use piping mode from stdin if args.is_empty() && cli.json { let config = crate::types::Config { - piping: false, - silent: cli.silent, - input_mode: crate::types::InputMode::Json, - show_timers: true, - width: None, - format: crate::types::DisplayFormat::from_str(&cli.format), - legend_style: cli.legend.clone(), - summary_style: cli.summary.clone(), - log_prefix_style: crate::types::LogPrefixStyle::from_str( - &cli.log_prefix, - ), - log_line_limit: cli.log_lines, + piping: false, + silent: cli.silent, + input_mode: crate::types::InputMode::Json, + show_timers: true, + width: None, + format: crate::types::DisplayFormat::from_str(&cli.format), + legend_style: cli.legend.clone(), + summary_style: cli.summary.clone(), }; let stdin = io::stdin(); @@ -201,8 +179,6 @@ pub fn run() -> eyre::Result<()> { cli.format.clone(), cli.legend.clone(), cli.summary.clone(), - cli.log_prefix.clone(), - cli.log_lines, )?; Ok(()) }, @@ -212,18 +188,14 @@ pub fn run() -> eyre::Result<()> { // If no args provided and --json is set, use piping mode from stdin if args.is_empty() && cli.json { let config = crate::types::Config { - piping: false, - silent: cli.silent, - input_mode: crate::types::InputMode::Json, - show_timers: true, - width: None, - format: crate::types::DisplayFormat::from_str(&cli.format), - legend_style: cli.legend.clone(), - summary_style: cli.summary.clone(), - log_prefix_style: crate::types::LogPrefixStyle::from_str( - &cli.log_prefix, - ), - log_line_limit: cli.log_lines, + piping: false, + silent: cli.silent, + input_mode: crate::types::InputMode::Json, + show_timers: true, + width: None, + format: crate::types::DisplayFormat::from_str(&cli.format), + legend_style: cli.legend.clone(), + summary_style: cli.summary.clone(), }; let stdin = io::stdin(); @@ -246,8 +218,6 @@ pub fn run() -> eyre::Result<()> { cli.format.clone(), cli.legend.clone(), cli.summary.clone(), - cli.log_prefix.clone(), - cli.log_lines, )?; Ok(()) }, @@ -269,10 +239,6 @@ pub fn run() -> eyre::Result<()> { format: crate::types::DisplayFormat::from_str(&cli.format), legend_style: cli.legend.clone(), summary_style: cli.summary.clone(), - log_prefix_style: crate::types::LogPrefixStyle::from_str( - &cli.log_prefix, - ), - log_line_limit: cli.log_lines, }; let stdin = io::stdin(); @@ -314,8 +280,6 @@ fn run_nix_build_wrapper( format: String, legend_style: String, summary_style: String, - log_prefix: String, - log_lines: Option, ) -> eyre::Result<()> { // Validate that at least one package/flake is specified if package_and_rom_args.is_empty() { @@ -346,8 +310,6 @@ fn run_nix_build_wrapper( format, legend_style, summary_style, - crate::types::LogPrefixStyle::from_str(&log_prefix), - log_lines, )?; if exit_code != 0 { std::process::exit(exit_code); @@ -363,8 +325,6 @@ fn run_nix_shell_wrapper( format: String, legend_style: String, summary_style: String, - log_prefix: String, - log_lines: Option, ) -> eyre::Result<()> { // Validate that at least one package/flake is specified if package_and_rom_args.is_empty() { @@ -400,8 +360,6 @@ fn run_nix_shell_wrapper( format, legend_style, summary_style, - crate::types::LogPrefixStyle::from_str(&log_prefix), - log_lines, )?; if exit_code != 0 { @@ -433,8 +391,6 @@ fn run_nix_develop_wrapper( format: String, legend_style: String, summary_style: String, - log_prefix: String, - log_lines: Option, ) -> eyre::Result<()> { // Validate that at least one package/flake is specified (can be empty for // current flake) develop without args is valid (uses current directory's @@ -463,8 +419,6 @@ fn run_nix_develop_wrapper( format, legend_style, summary_style, - crate::types::LogPrefixStyle::from_str(&log_prefix), - log_lines, )?; if exit_code != 0 { @@ -496,8 +450,6 @@ fn run_monitored_command( format_str: String, legend_style_str: String, summary_style_str: String, - log_prefix_style: crate::types::LogPrefixStyle, - log_line_limit: Option, ) -> eyre::Result { use std::{ io::{BufRead, BufReader}, @@ -529,13 +481,6 @@ fn run_monitored_command( let start_time = Arc::new(Mutex::new(crate::state::current_time())); let start_time_clone = start_time.clone(); - // Buffer for build logs - collected and passed to Display for coordinated - // rendering - let log_buffer = - Arc::new(Mutex::new(std::collections::VecDeque::::new())); - let log_buffer_clone = log_buffer.clone(); - let log_buffer_render = log_buffer.clone(); - // Spawn thread to read and parse stderr (where nix outputs logs) let stderr_thread = thread::spawn(move || { use tracing::debug; @@ -550,62 +495,19 @@ fn run_monitored_command( if let Ok(action) = serde_json::from_str::(json_line) { debug!("Parsed JSON message #{}: {:?}", json_count, action); - // Process the action first to update state + // Print messages immediately to stdout + if let cognos::Actions::Message { msg, .. } = &action { + println!("{msg}"); + } + let mut state = state_clone.lock().unwrap(); let derivation_count_before = state.derivation_infos.len(); - crate::update::process_message(&mut state, action.clone()); + crate::update::process_message(&mut state, action); crate::update::maintain_state( &mut state, crate::state::current_time(), ); let derivation_count_after = state.derivation_infos.len(); - - // Now handle build log messages after state is updated - // Buffer them for coordinated rendering with the display - match &action { - cognos::Actions::Message { msg, .. } => { - let mut logs = log_buffer_clone.lock().unwrap(); - logs.push_back(msg.clone()); - // Keep only recent logs based on limit - if let Some(limit) = log_line_limit { - while logs.len() > limit { - logs.pop_front(); - } - } - }, - cognos::Actions::Result { - fields, - activity, - id, - } => { - // Build log lines come as Result actions with FileTransfer - // activity (101) and fields containing just the log - // text: fields = ["log line text"] - if matches!(activity, cognos::Activities::FileTransfer) - && !fields.is_empty() - { - if let Some(log_text) = fields[0].as_str() { - // Get the activity prefix (e.g., "hello> ") - let use_color = !silent; - let prefix = state - .get_activity_prefix(*id, &log_prefix_style, use_color) - .unwrap_or_default(); - - let prefixed_log = format!("{prefix}{log_text}"); - let mut logs = log_buffer_clone.lock().unwrap(); - logs.push_back(prefixed_log); - // Keep only recent logs based on limit - if let Some(limit) = log_line_limit { - while logs.len() > limit { - logs.pop_front(); - } - } - } - } - }, - _ => {}, - } - if derivation_count_after != derivation_count_before { debug!( "Derivation count changed: {} -> {}", @@ -616,16 +518,9 @@ fn run_monitored_command( debug!("Failed to parse JSON: {}", json_line); } } else { - // Non-JSON lines, buffer them + // Non-JSON lines, pass through non_json_count += 1; - let mut logs = log_buffer_clone.lock().unwrap(); - logs.push_back(line.clone()); - // Keep only recent logs based on limit - if let Some(limit) = log_line_limit { - while logs.len() > limit { - logs.pop_front(); - } - } + println!("{line}"); } } debug!( @@ -688,16 +583,13 @@ fn run_monitored_command( || !state.full_summary.planned_builds.is_empty(); if !silent { - // Get buffered logs for coordinated rendering - let logs: Vec = - log_buffer_render.lock().unwrap().iter().cloned().collect(); - if has_activity || state.progress_state != ProgressState::JustStarted { // Clear any previous timer display if last_timer_display.is_some() { + display.clear_previous().ok(); last_timer_display = None; } - let _ = display.render(&state, &logs); + let _ = display.render(&state, &[]); } else { // Show initial timer while waiting for activity let start = *start_time_clone.lock().unwrap(); @@ -707,7 +599,8 @@ fn run_monitored_command( // Only update if changed (to avoid flicker) if last_timer_display.as_ref() != Some(&timer_text) { - let _ = display.render(&state, &logs); + display.clear_previous().ok(); + eprintln!("{timer_text}"); last_timer_display = Some(timer_text); } } diff --git a/rom/src/display.rs b/rom/src/display.rs index 1e0b26e..d8cb720 100644 --- a/rom/src/display.rs +++ b/rom/src/display.rs @@ -114,7 +114,7 @@ impl Display { let mut lines = Vec::new(); - // Print build logs ABOVE the graph + // Print accumulated logs first (these go above the tree) for log in logs { lines.push(log.clone()); } @@ -153,8 +153,6 @@ impl Display { } pub fn render_final(&mut self, state: &State) -> io::Result<()> { - tracing::debug!("render_final called"); - // Clear any previous render self.clear_previous()?; @@ -182,8 +180,6 @@ impl Display { }, } - tracing::debug!("render_final: {} lines to print", lines.len()); - // Print final output (don't track last_lines since this is final) for line in lines { writeln!(self.writer, "{line}")?; @@ -211,10 +207,8 @@ impl Display { let failed = state.full_summary.failed_builds.len(); let planned = state.full_summary.planned_builds.len(); - let duration = current_time() - state.start_time; - - // Always print summary (like NOM's "Finished at HH:MM:SS after Xs") if running > 0 || completed > 0 || failed > 0 || planned > 0 { + let duration = current_time() - state.start_time; lines.push(format!( "{} {} {} │ {} {} │ {} {} │ {} {} │ {} {}", self.colored("━", Color::Blue), @@ -229,18 +223,6 @@ impl Display { self.colored("⏱", Color::Grey), self.format_duration(duration) )); - } else { - // Nothing built - just show "Finished after Xs" - let now = chrono::Local::now(); - let time_str = now.format("%H:%M:%S"); - lines.push(format!( - "{} {}", - self.colored(&format!("Finished at {time_str}"), Color::Green), - self.colored( - &format!("after {}", self.format_duration(duration)), - Color::Green - ) - )); } lines @@ -698,23 +680,11 @@ impl Display { if let Some(info) = state.get_derivation_info(*drv_id) { let name = &info.name.name; let elapsed = current_time() - build.start; - - // Format time info - let mut time_info = String::new(); - if let Some(estimate_secs) = build.estimate { - let remaining = estimate_secs.saturating_sub(elapsed as u64); - time_info.push_str(&format!( - "∅ {} ", - self.format_duration(remaining as f64) - )); - } - time_info.push_str(&self.format_duration(elapsed)); - lines.push(format!( " {} {} {}", self.colored("⏵", Color::Yellow), name, - time_info + self.format_duration(elapsed) )); } } @@ -984,19 +954,8 @@ impl Display { } } - // Time information + // Time elapsed let elapsed = current_time() - build_info.start; - - // Show estimate if available - if let Some(estimate_secs) = build_info.estimate { - let remaining = estimate_secs.saturating_sub(elapsed as u64); - line.push_str(&self.colored( - &format!(" ∅ {}", self.format_duration(remaining as f64)), - Color::DarkGrey, - )); - } - - // Show elapsed time line.push_str(&self.colored( &format!(" ⏱ {}", self.format_duration(elapsed)), Color::DarkGrey, diff --git a/rom/src/lib.rs b/rom/src/lib.rs index 5c7acc8..ac668ed 100644 --- a/rom/src/lib.rs +++ b/rom/src/lib.rs @@ -1,5 +1,4 @@ //! ROM - Rust Output Monitor -pub mod cache; pub mod cli; pub mod display; pub mod error; diff --git a/rom/src/monitor.rs b/rom/src/monitor.rs index 5c1f30a..18e23b7 100644 --- a/rom/src/monitor.rs +++ b/rom/src/monitor.rs @@ -1,15 +1,12 @@ //! Monitor module for orchestrating state updates and display rendering - use std::{ io::{BufRead, Write}, time::Duration, }; use cognos::Host; -use tracing::debug; use crate::{ - cache::BuildReportCache, display::{Display, DisplayConfig, LegendStyle, SummaryStyle}, error::{Result, RomError}, state::{ @@ -57,12 +54,7 @@ impl Monitor { }; let display = Display::new(writer, display_config)?; - let mut state = State::new(); - - // Load build cache for predictions - let cache_path = BuildReportCache::default_cache_path(); - let cache = BuildReportCache::new(cache_path); - state.build_cache = cache.load(); + let state = State::new(); Ok(Self { state, @@ -98,14 +90,6 @@ impl Monitor { self.display.render_final(&self.state)?; } - // Save build cache for future predictions - let cache_path = BuildReportCache::default_cache_path(); - let cache = BuildReportCache::new(cache_path); - if let Err(e) = cache.save(&self.state.build_cache) { - debug!("Failed to save build cache: {}", e); - // Don't fail the build if cache save fails - } - // Return error code if there were failures if self.state.has_errors() { return Err(RomError::BuildFailed); @@ -156,6 +140,10 @@ impl Monitor { /// Process a human-readable line fn process_human_line(&mut self, line: &str) -> Result { + // Parse human-readable nix output + // This is a simplified version - the full implementation would need + // comprehensive parsing of nix's output format + let line = line.trim(); // Skip empty lines @@ -282,8 +270,10 @@ impl Monitor { // Extract number of paths if present let words: Vec<&str> = line.split_whitespace().collect(); if words.len() >= 2 { - if let Ok(count) = words[1].parse::() { - debug!("Copying {} paths", count); + if let Ok(_count) = words[1].parse::() { + // XXX: This is a PlanCopies message, we'll probably track this + // For now just acknowledge it, and let future work decide how + // we should go around doing it. return Ok(true); } } diff --git a/rom/src/state.rs b/rom/src/state.rs index 7f7fcfd..cc47ee7 100644 --- a/rom/src/state.rs +++ b/rom/src/state.rs @@ -360,7 +360,6 @@ pub struct State { pub full_summary: DependencySummary, pub forest_roots: Vec, pub build_reports: HashMap>, - pub build_cache: HashMap<(String, String), Vec>, pub start_time: f64, pub progress_state: ProgressState, pub store_path_ids: HashMap, @@ -372,8 +371,6 @@ pub struct State { pub traces: Vec, pub build_platform: Option, pub evaluation_state: EvalInfo, - pub builds_activity: Option, - pub success_tokens: u64, next_store_path_id: StorePathId, next_derivation_id: DerivationId, } @@ -393,7 +390,6 @@ impl State { full_summary: DependencySummary::default(), forest_roots: Vec::new(), build_reports: HashMap::new(), - build_cache: HashMap::new(), start_time: current_time(), progress_state: ProgressState::JustStarted, store_path_ids: HashMap::new(), @@ -405,8 +401,6 @@ impl State { traces: Vec::new(), build_platform: None, evaluation_state: EvalInfo::default(), - builds_activity: None, - success_tokens: 0, next_store_path_id: 0, next_derivation_id: 0, } @@ -703,106 +697,6 @@ impl State { .copied() .collect() } - - /// Get the activity prefix for a given activity ID by walking up the parent - /// chain to find a Build activity and extracting its derivation name. - /// Returns a prefix like "hello> " suitable for prepending to log lines. - /// If `use_color` is true and stderr is a TTY, the prefix will be blue. - /// The `prefix_style` determines whether to use short (pname only), full, or - /// no prefix. - #[must_use] - pub fn get_activity_prefix( - &self, - activity_id: ActivityId, - prefix_style: &crate::types::LogPrefixStyle, - use_color: bool, - ) -> Option { - use cognos::Activities; - - use crate::types::LogPrefixStyle; - - // If prefix style is None, return empty string - if matches!(prefix_style, LogPrefixStyle::None) { - return Some(String::new()); - } - - let mut current_id = activity_id; - let max_depth = 10; // Prevent infinite loops - let mut depth = 0; - - while depth < max_depth { - if let Some(activity) = self.activities.get(¤t_id) { - // Check if this is a Build activity (type 105) - if activity.activity == Activities::Build as u8 { - // Extract derivation path from the text field - // The text field typically contains something like: - // "building '/nix/store/...-hello-2.10.drv'" - if let Some(drv) = extract_derivation_from_text(&activity.text) { - // Look up the DerivationInfo for this derivation - let drv_id = self.derivation_ids.get(&drv); - let name = if matches!(prefix_style, LogPrefixStyle::Short) { - // Try to use pname if available - if let Some(id) = drv_id { - if let Some(drv_info) = self.derivation_infos.get(id) { - if let Some(pname) = &drv_info.pname { - pname.clone() - } else { - drv.name.clone() - } - } else { - drv.name.clone() - } - } else { - drv.name.clone() - } - } else { - // Full style - use full derivation name - drv.name.clone() - }; - - // Apply color if requested and stderr is a TTY - let colored_name = if use_color - && std::io::IsTerminal::is_terminal(&std::io::stderr()) - { - format!("\x1b[34m{name}\x1b[0m") - } else { - name - }; - - return Some(format!("{colored_name}> ")); - } - } - - // Move to parent activity - if let Some(parent_id) = activity.parent { - if parent_id == 0 { - break; // Reached root - } - current_id = parent_id; - depth += 1; - } else { - break; - } - } else { - break; - } - } - - None - } -} - -/// Extract derivation from activity text like "building -/// '/nix/store/...-hello-2.10.drv'" Returns the Derivation object -fn extract_derivation_from_text(text: &str) -> Option { - // Look for .drv path in text - if let Some(start) = text.find("/nix/store/") { - if let Some(end) = text[start..].find(".drv") { - let drv_path = &text[start..start + end + 4]; // Include .drv - return Derivation::parse(drv_path); - } - } - None } #[must_use] diff --git a/rom/src/types.rs b/rom/src/types.rs index 26eb8cd..b355ec9 100644 --- a/rom/src/types.rs +++ b/rom/src/types.rs @@ -11,17 +11,6 @@ pub enum DisplayFormat { Dashboard, } -/// Log prefix style for build logs -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum LogPrefixStyle { - /// Just package name (pname) - Short, - /// Full derivation name with version - Full, - /// No prefix - None, -} - /// Summary display style #[derive(Debug, Clone, PartialEq, Eq)] pub enum SummaryStyle { @@ -45,18 +34,6 @@ impl SummaryStyle { } } -impl LogPrefixStyle { - #[must_use] - pub fn from_str(s: &str) -> Self { - match s.to_lowercase().as_str() { - "short" => Self::Short, - "full" => Self::Full, - "none" => Self::None, - _ => Self::Short, - } - } -} - impl DisplayFormat { #[must_use] pub fn from_str(s: &str) -> Self { @@ -73,40 +50,34 @@ impl DisplayFormat { #[derive(Debug, Clone)] pub struct Config { /// Whether we're piping output through - pub piping: bool, + pub piping: bool, /// Silent mode - minimal output - pub silent: bool, + pub silent: bool, /// Input parsing mode - pub input_mode: InputMode, + pub input_mode: InputMode, /// Show completion times - pub show_timers: bool, + pub show_timers: bool, /// Terminal width override - pub width: Option, + pub width: Option, /// Display format - pub format: DisplayFormat, + pub format: DisplayFormat, /// Legend display style - pub legend_style: String, + pub legend_style: String, /// Summary display style - pub summary_style: String, - /// Log prefix style for build logs - pub log_prefix_style: LogPrefixStyle, - /// Maximum number of log lines to display (None = unlimited) - pub log_line_limit: Option, + pub summary_style: String, } impl Default for Config { fn default() -> Self { Self { - piping: false, - silent: false, - input_mode: InputMode::Human, - show_timers: true, - width: None, - format: DisplayFormat::Tree, - legend_style: "table".to_string(), - summary_style: "concise".to_string(), - log_prefix_style: LogPrefixStyle::Short, - log_line_limit: None, + piping: false, + silent: false, + input_mode: InputMode::Human, + show_timers: true, + width: None, + format: DisplayFormat::Tree, + legend_style: "table".to_string(), + summary_style: "concise".to_string(), } } } @@ -132,8 +103,6 @@ mod tests { assert_eq!(config.input_mode, InputMode::Human); assert!(config.show_timers); assert_eq!(config.format, DisplayFormat::Tree); - assert_eq!(config.log_prefix_style, LogPrefixStyle::Short); - assert_eq!(config.log_line_limit, None); } #[test] diff --git a/rom/src/update.rs b/rom/src/update.rs index 3e3a0a8..0524dfb 100644 --- a/rom/src/update.rs +++ b/rom/src/update.rs @@ -3,29 +3,25 @@ use cognos::{Actions, Activities, Host, Id, ProgressState, Verbosity}; use tracing::{debug, trace}; -use crate::{ - cache::BuildReportCache, - state::{ - ActivityProgress, - ActivityStatus, - BuildFail, - BuildInfo, - BuildReport, - BuildStatus, - CompletedBuildInfo, - CompletedTransferInfo, - Derivation, - DerivationId, - FailType, - FailedBuildInfo, - InputDerivation, - State, - StorePath, - StorePathId, - StorePathState, - TransferInfo, - current_time, - }, +use crate::state::{ + ActivityProgress, + ActivityStatus, + BuildFail, + BuildInfo, + BuildStatus, + CompletedBuildInfo, + CompletedTransferInfo, + Derivation, + DerivationId, + FailType, + FailedBuildInfo, + InputDerivation, + State, + StorePath, + StorePathId, + StorePathState, + TransferInfo, + current_time, }; /// Process a nix JSON message and update state @@ -100,19 +96,10 @@ fn handle_start( 109 => handle_query_path_info_start(state, id, &text, &fields, now), /* QueryPathInfo */ 110 => handle_post_build_hook_start(state, id, &text, &fields, now), /* PostBuildHook */ 101 => handle_file_transfer_start(state, id, &text, &fields, now), /* FileTransfer */ - 100 => handle_copy_path_start(state, id, &text, &fields, now), /* CopyPath */ - 104 => { - // Builds activity - track this as the top-level builds activity - if state.builds_activity.is_none() { - state.builds_activity = Some(id); - true - } else { - false - } - }, - 102 | 103 | 106 | 107 | 111 | 112 => { - // Realise, CopyPaths, OptimiseStore, VerifyPaths, BuildWaiting, FetchTree - // These activities have no fields and are just tracked + 100 => handle_copy_path_start(state, id, &text, &fields, now), // CopyPath + 102 | 103 | 104 | 106 | 107 | 111 | 112 => { + // Realise, CopyPaths, Builds, OptimiseStore, VerifyPaths, BuildWaiting, + // FetchTree These activities have no fields and are just tracked true }, _ => { @@ -294,12 +281,11 @@ fn handle_result( match result_type { 100 => { - // FileLinked: 2 int fields (linked count, total count) + // FileLinked: 2 int fields if fields.len() >= 2 { - let linked = fields[0].as_u64().unwrap_or(0); - let total = fields[1].as_u64().unwrap_or(0); - debug!("FileLinked: {}/{}", linked, total); - // File linking is reported but doesn't need state tracking + let _linked = fields[0].as_u64(); + let _total = fields[1].as_u64(); + // TODO: Track file linking progress } false }, @@ -314,18 +300,17 @@ fn handle_result( 102 => { // UntrustedPath: 1 text field (store path) if let Some(path_str) = fields.first().and_then(|f| f.as_str()) { - debug!("Untrusted path reported: {}", path_str); - state - .nix_errors - .push(format!("Untrusted path: {}", path_str)); - return true; + debug!("Untrusted path: {}", path_str); + // TODO: Track untrusted paths } false }, 103 => { // CorruptedPath: 1 text field (store path) if let Some(path_str) = fields.first().and_then(|f| f.as_str()) { - state.nix_errors.push(format!("Corrupted path: {path_str}")); + state + .nix_errors + .push(format!("Corrupted path: {path_str}")); return true; } false @@ -349,19 +334,6 @@ fn handle_result( fields[2].as_u64(), fields[3].as_u64(), ) { - // If this progress is for the Builds activity, track success tokens - if state.builds_activity == Some(id) { - if let Some(activity) = state.activities.get(&id) { - if let Some(prev_progress) = &activity.progress { - let new_done = done.saturating_sub(prev_progress.done); - if new_done > 0 { - state.success_tokens = - state.success_tokens.saturating_add(new_done); - } - } - } - } - if let Some(activity) = state.activities.get_mut(&id) { activity.progress = Some(ActivityProgress { done, @@ -378,13 +350,9 @@ fn handle_result( 106 => { // SetExpected: 2 int fields (activity type, count) if fields.len() >= 2 { - let activity_type = fields[0].as_u64().unwrap_or(0); - let expected_count = fields[1].as_u64().unwrap_or(0); - debug!( - "SetExpected: activity_type={}, count={}", - activity_type, expected_count - ); - // Expected counts are informational and don't affect state tracking + let _activity_type = fields[0].as_u64(); + let _expected_count = fields[1].as_u64(); + // TODO: Track expected counts } false }, @@ -400,7 +368,7 @@ fn handle_result( // FetchStatus: 1 text field if let Some(status) = fields.first().and_then(|f| f.as_str()) { debug!("Fetch status: {}", status); - // Fetch status is informational + // TODO: Track fetch status } false }, @@ -411,50 +379,6 @@ fn handle_result( } } -/// Get build time estimate from cache -fn get_build_estimate( - state: &State, - derivation_name: &str, - host: &Host, -) -> Option { - // Use pname if available, otherwise derivation name - let lookup_name = derivation_name.to_string(); - let host_str = host.name(); - - BuildReportCache::calculate_median( - state - .build_cache - .get(&(host_str.to_string(), lookup_name))? - .as_slice(), - ) -} - -/// Record completed build for future predictions -fn record_build_completion( - state: &mut State, - derivation_name: String, - platform: Option, - start: f64, - end: f64, - host: &Host, -) { - let duration_secs = end - start; - let completed_at = std::time::SystemTime::now(); - - let report = BuildReport { - derivation_name: derivation_name.clone(), - platform: platform.unwrap_or_default(), - duration_secs, - completed_at, - host: host.name().to_string(), - success: true, - }; - - // Store in state for later CSV persistence - let key = (host.name().to_string(), derivation_name); - state.build_cache.entry(key).or_default().push(report); -} - fn handle_build_start( state: &mut State, id: Id, @@ -478,16 +402,13 @@ fn handle_build_start( if let Some(drv_path) = drv_path { debug!("Extracted derivation path: {}", drv_path); if let Some(drv) = Derivation::parse(&drv_path) { - let drv_id = state.get_or_create_derivation_id(drv.clone()); + let drv_id = state.get_or_create_derivation_id(drv); let host = extract_host(text); - // Get build time estimate from cache - let estimate = get_build_estimate(state, &drv.name, &host); - let build_info = BuildInfo { start: now, host, - estimate, + estimate: None, activity_id: Some(id), }; @@ -523,42 +444,21 @@ fn handle_build_start( false } -fn handle_build_stop(state: &mut State, id: Id, now: f64) -> bool { - // Check if we have success tokens to consume - if state.success_tokens > 0 { - // Find the derivation associated with this activity - for (drv_id, info) in state.derivation_infos.clone().iter() { - if let BuildStatus::Building(build_info) = &info.build_status { - if build_info.activity_id == Some(id) { - // Consume a success token and mark build as complete - state.success_tokens = state.success_tokens.saturating_sub(1); - state.update_build_status(*drv_id, BuildStatus::Built { - info: build_info.clone(), - end: now, - }); - - // Record build completion for future predictions - record_build_completion( - state, - info.name.name.clone(), - info.platform.clone(), - build_info.start, - now, - &build_info.host, - ); - - debug!( - "Build completed for derivation {} (success_tokens: {})", - drv_id, state.success_tokens - ); - return true; - } - } +fn handle_build_stop(state: &mut State, id: Id, _now: f64) -> bool { + // Find the derivation associated with this activity + for (drv_id, info) in &state.derivation_infos { + match &info.build_status { + BuildStatus::Building(build_info) + if build_info.activity_id == Some(id) => + { + // Build was stopped but not marked as completed + // It might be cancelled + debug!("Build stopped for derivation {}", drv_id); + return false; + }, + _ => {}, } } - - // No success tokens - build was stopped without completion signal - debug!("Build stopped for activity {} without success token", id); false }