diff --git a/.github/report.jpg b/.github/report.jpg deleted file mode 100644 index e06aa32..0000000 Binary files a/.github/report.jpg and /dev/null differ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 6967dd0..cd79a55 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -53,14 +53,14 @@ jobs: arch: amd64 runner: ubuntu-24.04 run: | - sudo apt install -y pkg-config libfreetype6-dev libfontconfig1-dev + rustup target add x86_64-unknown-linux-musl - name: 🐥 Linux ARM64 os: linux arch: arm64 runner: ubuntu-24.04-arm run: | - sudo apt install -y pkg-config libfreetype6-dev libfontconfig1-dev + rustup target add aarch64-unknown-linux-musl - name: 🍎 MacOS AMD64 os: macos diff --git a/Cargo.lock b/Cargo.lock index b479de7..381d08a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,143 +1,74 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] +version = 4 [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys", ] [[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" +name = "anyhow" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytemuck" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.0.92" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.6", -] +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "clap" -version = "4.5.26" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -145,9 +76,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -157,9 +88,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -169,272 +100,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] - -[[package]] -name = "core-text" -version = "20.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" -dependencies = [ - "core-foundation", - "core-graphics", - "foreign-types", - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading", -] - -[[package]] -name = "dwrote" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" -dependencies = [ - "lazy_static", - "libc", - "winapi", - "wio", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "fdeflate" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "float-ord" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] -name = "font-kit" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" -dependencies = [ - "bitflags 2.5.0", - "byteorder", - "core-foundation", - "core-graphics", - "core-text", - "dirs", - "dwrote", - "float-ord", - "freetype-sys", - "lazy_static", - "libc", - "log", - "pathfinder_geometry", - "pathfinder_simd", - "walkdir", - "winapi", - "yeslogic-fontconfig-sys", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "freetype-sys" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "getrandom" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gif" -version = "0.12.0" +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" -dependencies = [ - "color_quant", - "weezl", -] +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "heck" @@ -443,239 +117,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[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 = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "jpeg-decoder", - "num-traits", - "png", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - -[[package]] -name = "js-sys" -version = "0.3.69" +name = "is_terminal_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "libloading" -version = "0.8.3" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.5.0", - "libc", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", - "simd-adler32", -] +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "ntapi" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" dependencies = [ "winapi", ] [[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "pathfinder_geometry" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" -dependencies = [ - "log", - "pathfinder_simd", -] - -[[package]] -name = "pathfinder_simd" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "chrono", - "font-kit", - "image", - "lazy_static", - "num-traits", - "pathfinder_geometry", - "plotters-backend", - "plotters-bitmap", - "plotters-svg", - "ttf-parser", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-bitmap" -version = "0.3.7" +name = "objc2-core-foundation" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "gif", - "image", - "plotters-backend", + "bitflags", ] [[package]] -name = "plotters-svg" -version = "0.3.7" +name = "objc2-io-kit" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" dependencies = [ - "plotters-backend", + "libc", + "objc2-core-foundation", ] [[package]] -name = "png" -version = "0.17.13" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -684,108 +181,51 @@ dependencies = [ name = "procmon" version = "0.2.0" dependencies = [ + "anyhow", "clap", - "plotters", "serde", "sysinfo", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] -name = "rayon" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_users" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ - "semver", + "serde_core", + "serde_derive", ] [[package]] -name = "same-file" -version = "1.0.6" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "strsim" version = "0.11.1" @@ -794,9 +234,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -805,141 +245,29 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.1" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +checksum = "d03c61d2a49c649a15c407338afe7accafde9dac869995dccb73e5f7ef7d9034" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "rayon", + "objc2-core-foundation", + "objc2-io-kit", "windows", ] -[[package]] -name = "thiserror" -version = "1.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ttf-parser" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "weezl" -version = "0.1.8" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "winapi" @@ -957,15 +285,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -974,51 +293,54 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.57.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-targets 0.52.6", + "windows-core", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", - "windows-targets 0.52.6", + "windows-strings", ] [[package]] -name = "windows-implement" -version = "0.57.0" +name = "windows-future" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] -name = "windows-interface" -version = "0.57.0" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -1026,169 +348,64 @@ dependencies = [ ] [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-sys" -version = "0.52.0" +name = "windows-numerics" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-targets 0.52.6", + "windows-core", + "windows-link", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[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_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[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_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[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_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wio" -version = "0.2.2" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "winapi", + "windows-link", ] [[package]] -name = "yeslogic-fontconfig-sys" -version = "6.0.0" +name = "windows-threading" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "dlib", - "once_cell", - "pkg-config", + "windows-link", ] diff --git a/Cargo.toml b/Cargo.toml index 110c540..1cab9e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "procmon" version = "0.2.0" -edition = "2021" +edition = "2024" [dependencies] -clap = { version = "4.5.26", features = ["derive", "env", "string"] } -plotters = "0.3.7" -serde = { version = "1.0.217", features = ["serde_derive", "derive"] } -sysinfo = "0.33.1" +anyhow = "1.0.102" +clap = { version = "4.5.60", features = ["derive", "env", "string"] } +serde = { version = "1.0.228", features = ["serde_derive", "derive"] } +sysinfo = "0.38.3" + diff --git a/README.md b/README.md index a8072a3..6988e49 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,39 @@ A command line utility that spawns a process and produces a `csv` report on its resource usage. ```bash -procmon --help -procmon -- [COMMAND] +Usage: procmon [OPTIONS] [COMMAND]... + +Arguments: + [COMMAND]... Command to run + +Options: + -r, --report Output path for the generated report [env: PM_REPORT=] [default: procmon.csv] + -i, --interval How often to probe the process for details in milliseconds [env: PM_INTERVAL=] [default: 200] + -m, --mem-units What units to use for recording memory [env: PM_MEM_UNITS=] [default: mb] [possible values: mb, kb, b] + -t, --time-units What units to use for recording time [env: PM_TIME_UNITS=] [default: ms] [possible values: s, ms] + -o, --override-report Override report file if exists + --no-cpu Don't measure CPU usage [env: PM_NO_CPU=] + --no-memory Don't measure memory usage [env: PM_NO_MEMORY=] + --no-disk Don't measure disk usage [env: PM_NO_DISK=] + -h, --help Print help ``` +# Usage + ```bash procmon -- node -e "setTimeout(() => console.log('Sup'), 4000)" ``` -This will produce a file named something similar to `report.csv` +This will produce a file named `procmon.csv` ```bash -procmon --report something -- node -e "setTimeout(() => console.log('Sup'), 4000)" +procmon --report something.csv -- node -e "setTimeout(() => console.log('Sup'), 4000)" ``` -This will produce a folder containing the report - -``` -/something - report.csv - report.png -``` +This will produce a report called `something.csv` The csv file looks like: -``` +```javascript time_s,cpu,memory_mb,disk_read,disk_write 0.000,0,0,0,0 0.065,0,16,5976064,0 @@ -41,10 +50,6 @@ time_s,cpu,memory_mb,disk_read,disk_write 4.145,0,0,0,0 ``` -The png looks like: - - - # Installation ## MacOS @@ -81,10 +86,6 @@ mkdir -p $HOME/.local/procmon curl -L --url https://github.com/alshdavid/procmon/releases/latest/download/linux-amd64.tar.gz | tar -xvzf - -C $HOME/.local/procmon ``` -## Windows - -I'm not good at PowerShell - follow the same steps as the Linux/MacOS scripts - ## Credit [Matt Jones](https://github.com/mattcompiles) diff --git a/justfile b/justfile index ca961e9..f769f16 100644 --- a/justfile +++ b/justfile @@ -23,9 +23,9 @@ else \ target := \ if \ - os + arch == "linuxamd64" { "x86_64-unknown-linux-gnu" } \ + os + arch == "linuxamd64" { "x86_64-unknown-linux-musl" } \ else if \ - os + arch == "linuxarm64" { "aarch64-unknown-linux-gnu" } \ + os + arch == "linuxarm64" { "aarch64-unknown-linux-musl" } \ else if \ os + arch == "macosamd64" { "x86_64-apple-darwin" } \ else if\ diff --git a/rust-toolchain b/rust-toolchain index 79f25d0..089d189 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.84.0 \ No newline at end of file +1.94.0 \ No newline at end of file diff --git a/src/args.rs b/src/args.rs index 4266397..c98f7a6 100644 --- a/src/args.rs +++ b/src/args.rs @@ -13,11 +13,11 @@ pub struct Args { pub command: Vec, /// Output path for the generated report - #[arg(short = 'r', long = "report", env = "PM_REPORT", value_parser = parse_file_path, default_value = "procmon")] + #[arg(short = 'r', long = "report", env = "PM_REPORT", value_parser = parse_file_path, default_value = "procmon.csv")] pub report_path: PathBuf, /// How often to probe the process for details in milliseconds - #[arg(short = 'i', long = "interval", env = "PM_INTERVAL", value_parser = parse_duration, default_value = "250")] + #[arg(short = 'i', long = "interval", env = "PM_INTERVAL", value_parser = parse_duration, default_value = "200")] pub poll_interval: time::Duration, /// What units to use for recording memory @@ -41,8 +41,8 @@ pub struct Args { pub time_units: TimeUnits, /// Override report file if exists - #[arg(long = "no-override-report")] - pub no_override_report: bool, + #[arg(short = 'o', long = "override-report")] + pub override_report: bool, /// Don't measure CPU usage #[arg(long = "no-cpu", env = "PM_NO_CPU")] diff --git a/src/main.rs b/src/main.rs index 7e2b264..1bc0bc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,10 @@ #![deny(unused_crate_dependencies)] mod args; -mod plot; mod reporter; +use anyhow::Context; use clap::Parser; -use plot::generate_plot; use std::env; use std::process::Command; use std::process::Stdio; @@ -23,12 +22,12 @@ use crate::reporter::Columns; use crate::reporter::Reporter; use crate::reporter::Row; -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let reporter = match Reporter::new( &args.report_path, - &!args.no_override_report, + &args.override_report, Columns { cpu: !args.no_measure_cpu, memory: !args.no_measure_mem, @@ -38,20 +37,19 @@ fn main() { ) { Ok(v) => v, Err(msg) => { - println!("Error: {}", msg); - return; + return Err(anyhow::anyhow!("Error: {}", msg)); } }; let (sender, receiver) = channel::<(u32, Duration)>(); // Monitor - let h0 = { + let h0: thread::JoinHandle> = { let command = args.clone(); let reporter = reporter.clone(); thread::spawn(move || { - let (pid, start_time) = receiver.recv().unwrap(); + let (pid, start_time) = receiver.recv()?; let pid = Pid::from(pid as usize); // Please note that we use "new_all" to ensure that all list of @@ -62,39 +60,39 @@ fn main() { if sys.refresh_processes(ProcessesToUpdate::Some(&[pid]), true) == 0 { break; } - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Can't get the time"); + let info = sys.process(pid).context("Unable to get process")?; - let p = sys.process(pid).expect("Can't get process info"); + let now = SystemTime::now().duration_since(UNIX_EPOCH)?; let mut row = Row::default(); if !command.no_measure_cpu { - let cpu = p.cpu_usage(); + let cpu = info.cpu_usage(); row.cpu = Some(cpu.round() as u64); } if !command.no_measure_mem { - let memory = p.memory(); + let memory = info.memory(); row.memory = Some(memory); } if !command.no_measure_disk { - let disk = p.disk_usage(); + let disk = info.disk_usage(); row.disk_read = Some(disk.read_bytes); row.disk_write = Some(disk.written_bytes); } row.time = now - start_time; - reporter.write(row); + reporter.write(row)?; thread::sleep(command.poll_interval); } + + Ok(()) }) }; // Process - let h1 = { + let h1: thread::JoinHandle> = { let mut args = args.clone(); let reporter = reporter.clone(); @@ -105,7 +103,7 @@ fn main() { let mut command = Command::new(first); command.args(args.command); - command.current_dir(env::current_dir().unwrap()); + command.current_dir(env::current_dir()?); command.stdout(Stdio::inherit()); command.stdin(Stdio::inherit()); @@ -113,9 +111,7 @@ fn main() { command }; - let start_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Can't get the time"); + let start_time = SystemTime::now().duration_since(UNIX_EPOCH)?; reporter.write(Row { time: Duration::from_millis(0), @@ -123,15 +119,13 @@ fn main() { cpu: Some(0), disk_read: Some(0), disk_write: Some(0), - }); + })?; - let mut child = command.spawn().unwrap(); - sender.send((child.id(), start_time)).unwrap(); - child.wait().unwrap(); + let mut child = command.spawn()?; + sender.send((child.id(), start_time))?; + child.wait()?; - let end_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Can't get the time"); + let end_time = SystemTime::now().duration_since(UNIX_EPOCH)?; reporter.write(Row { time: end_time - start_time, @@ -139,155 +133,14 @@ fn main() { cpu: Some(0), disk_read: Some(0), disk_write: Some(0), - }); + })?; + + Ok(()) }) }; - h1.join().unwrap(); - h0.join().unwrap(); + h1.join().unwrap()?; + h0.join().unwrap()?; - generate_plot(&args.report_path, &reporter.rows.read().unwrap()).unwrap(); + Ok(()) } - -// fn main() { -// let report_file = cfg::get_report_file_path(); -// let polling_interval = cfg::get_polling_interval(); -// let target_pid = cfg::get_pid(); -// let mem_units = cfg::get_mem_units(); -// let time_units = cfg::get_time_units(); -// let columns = cfg::get_columns(); - -// let mut handles = Vec::>::new(); -// let duration: Arc>> = Arc::new(Mutex::new(None)); -// let (sender, receiver) = channel::<(u32, Option)>(); - -// let buffer = Arc::new(Mutex::new(Vec::::new())); - -// if report_file.to_string() != "stdout" { -// println!("[procmon] Polling: {:?}", polling_interval); -// println!("[procmon] Report: {}", report_file.to_string()); -// } - -// // Monitor -// { -// let report_file = report_file.clone(); -// let buffer = buffer.clone(); -// let columns = columns.clone(); -// let time_units = time_units.clone(); - -// handles.push(thread::spawn(move || { -// let (pid, start_time) = receiver.recv().unwrap(); -// // Please note that we use "new_all" to ensure that all list of -// // components, network interfaces, disks and users are already filled! - -// if report_file.to_string() != "stdout" { -// println!("[procmon] PID: {}", pid); -// } - -// let mut sys = System::new_all(); -// let pid = Pid::from(pid as usize); - -// buffer.lock().unwrap().push(columns.get_header()); - -// while sys.refresh_process(pid) { -// let now = SystemTime::now() -// .duration_since(UNIX_EPOCH) -// .expect("Can't get the time"); - -// let p = sys.process(pid).expect("Can't get process info"); - -// let disk = p.disk_usage(); -// let memory = p.memory() / mem_units as u64; -// let cpu = (p.cpu_usage()).round() as u64; - -// let start_time_ms = match start_time { -// Some(t) => t.as_millis(), -// None => (p.start_time() * 1000) as u128, -// }; - -// let run_time = match time_units { -// cfg::TimeUnits::Seconds => (now.as_millis() - start_time_ms) as f64 / 1000 as f64, -// cfg::TimeUnits::Milliseconds => (now.as_millis() - start_time_ms) as f64, -// }; - -// buffer.lock().unwrap().push(columns.new_string( -// run_time, -// cpu, -// memory, -// disk.written_bytes, -// disk.read_bytes, -// )); - -// thread::sleep(polling_interval); -// } -// })); -// } - -// // Process -// { -// let duration = duration.clone(); - -// handles.push(thread::spawn(move || { -// if let Some(pid) = target_pid { -// println!("[procmon] Using existing PID"); -// sender.send((pid, None)).unwrap(); -// return; -// } - -// let args: Vec = env::args().collect(); -// let command_segments_raw = &args[1..]; -// let mut segments: Vec = command_segments_raw.to_vec(); - -// let first = segments.remove(0); - -// let mut command = Command::new(first); -// command.args(segments); - -// command.current_dir(env::current_dir().unwrap()); - -// command.stdout(Stdio::inherit()); -// command.stdin(Stdio::inherit()); -// command.stderr(Stdio::inherit()); - -// let start_time = SystemTime::now() -// .duration_since(UNIX_EPOCH) -// .expect("Can't get the time"); - -// let mut child = command.spawn().unwrap(); -// sender.send((child.id(), Some(start_time))).unwrap(); -// child.wait().unwrap(); - -// let end_time = SystemTime::now() -// .duration_since(UNIX_EPOCH) -// .expect("Can't get the time"); - -// let time_elapsed = end_time - start_time; -// let mut d = duration.lock().unwrap(); -// *d = Some(time_elapsed); -// })); -// } - -// for handle in handles { -// handle.join().unwrap(); -// } - -// let duration = duration.lock().unwrap().unwrap(); -// let total_duration = match time_units { -// cfg::TimeUnits::Seconds => duration.as_secs() as f64, -// cfg::TimeUnits::Milliseconds => duration.as_millis() as f64, -// }; - -// buffer -// .lock() -// .unwrap() -// .push(columns.new_string(total_duration as f64, 0, 0, 0, 0)); -// fs::write(report_file.to_string(), buffer.lock().unwrap().join("\n")).unwrap(); - -// println!("[procmon] Report: {}", report_file.to_string()); - -// if duration.as_secs() < 10 { -// println!("[procmon] Duration: {}ms", duration.as_millis()); -// } else { -// println!("[procmon] Duration: {}s", duration.as_secs()); -// } -// } diff --git a/src/plot.rs b/src/plot.rs deleted file mode 100644 index 6b35342..0000000 --- a/src/plot.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::error::Error; - -use plotters::prelude::*; - -use crate::reporter::Row; - -pub fn generate_plot( - report_path: &std::path::Path, - rows: &[Row], -) -> Result<(), Box> { - let output_path = report_path.join("report.png"); - - let data_x_axis = rows - .iter() - .map(|r| r.time.as_millis()) - .collect::>(); - let data_x_max = *data_x_axis.iter().max().unwrap(); - - let data_cpu = rows - .iter() - .map(|r| r.cpu.unwrap() as usize) - .collect::>(); - let data_y_axis_cpu_max = *data_cpu.iter().max().unwrap() as u64; - let data_y_axis_cpu = rows - .iter() - .map(|r| (r.time.as_millis(), r.cpu.unwrap())) - .collect::>(); - - let data_mem = rows - .iter() - .map(|r| (r.memory.unwrap() / 1024) as usize) - .collect::>(); - let data_y_axis_mem_max = *data_mem.iter().max().unwrap() as u64; - let data_y_axis_mem = rows - .iter() - .map(|r| (r.time.as_millis(), (r.memory.unwrap() / 1024))) - .collect::>(); - let root = BitMapBackend::new(&output_path, (1920, 1080)).into_drawing_area(); - - root.fill(&WHITE)?; - - let mut chart = ChartBuilder::on(&root) - .margin(10) - .set_label_area_size(LabelAreaPosition::Left, 60) - .set_label_area_size(LabelAreaPosition::Right, 60) - .set_label_area_size(LabelAreaPosition::Bottom, 40) - .build_cartesian_2d(0..data_x_max, 0..data_y_axis_cpu_max)? - .set_secondary_coord(0..data_x_max, 0..data_y_axis_mem_max); - - chart - .configure_secondary_axes() - .y_desc("Ram Usage (mb)") - .y_label_formatter(&|v| format!("{}", v / 1024)) - .draw()?; - - chart - .configure_mesh() - .x_desc("Time (ms)".to_string()) - .disable_x_mesh() - .disable_y_mesh() - .x_labels(round_up(data_x_max as usize) / 1000) - .x_label_formatter(&|v| format!("{}", v / 1000)) - .y_label_formatter(&|v| format!("{} %", v)) - .y_desc("CPU Usage") - .draw()?; - - chart.draw_series(LineSeries::new(data_y_axis_cpu, &BLUE))?; - - if data_x_max > 2000 { - chart - .draw_secondary_series(LineSeries::new(data_y_axis_mem, &RED))? - .label(format!("Time: {:.2} s", data_x_max as f64 / 1000.0)); - } else { - chart - .draw_secondary_series(LineSeries::new(data_y_axis_mem, &RED))? - .label(format!("Time: {} ms", data_x_max)); - } - - chart - .configure_series_labels() - .background_style(RGBColor(128, 128, 128)) - .draw()?; - - // To avoid the IO failure being ignored silently, we manually call the present function - root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir"); - Ok(()) -} - -fn round_up(i: usize) -> usize { - let mut c = i; - loop { - if c.is_multiple_of(1000) { - return c; - } - c += 1; - } -} diff --git a/src/reporter.rs b/src/reporter.rs index b26f33e..10e4391 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -1,10 +1,9 @@ -use std::fs; -use std::fs::File; use std::fs::OpenOptions; use std::io::Write; use std::path::Path; -use std::sync::Arc; -use std::sync::RwLock; +use std::sync::mpsc::Sender; +use std::sync::mpsc::channel; +use std::thread::JoinHandle; use std::time::Duration; use crate::args::Args; @@ -26,122 +25,117 @@ pub struct Row { pub disk_write: Option, } +#[derive(Clone)] pub struct Reporter { - report_file: File, - columns: Columns, - args: Args, - pub rows: RwLock>, + tx_writer: Sender, } impl Reporter { pub fn new( - report_folder: &Path, + report_file: &Path, override_report: &bool, columns: Columns, args: Args, - ) -> Result, String> { - if report_folder.exists() { - if *override_report { - fs::remove_dir_all(report_folder).unwrap(); - } else { - return Err(format!( - "Report folder {} already exists", - report_folder.to_str().unwrap() - )); - } + ) -> anyhow::Result { + if !override_report && std::fs::exists(&report_file)? { + return Err(anyhow::anyhow!("Report {:?} already exists", report_file)); } - fs::create_dir(report_folder).unwrap(); + if std::fs::exists(&report_file)? { + std::fs::remove_file(&report_file)?; + } - let report_file = OpenOptions::new() + if let Some(parent_dir) = report_file.parent() + && !std::fs::exists(parent_dir)? + { + std::fs::create_dir_all(parent_dir)?; + } + + let mut report_file = OpenOptions::new() .append(true) .create_new(true) - .open(report_folder.join("report.csv")) - .unwrap(); + .open(report_file)?; - let mut header = vec![format!("time_{}", args.time_units.get_unit())]; - if columns.cpu { - header.push("cpu".to_string()); - } - if columns.memory { - header.push(format!("memory_{}", args.mem_units.get_unit())); - } - if columns.disk { - header.push("disk_read".to_string()); - header.push("disk_write".to_string()); - } + let (tx_writer, rx_write) = channel::(); - let reporter = Self { - report_file, - columns, - args, - rows: RwLock::new(vec![]), - }; + // Sender will fail if the thread dies, don't worry about propagating error message for now + let _h0: JoinHandle> = std::thread::spawn(move || { + let mut header = vec![format!("time_{}", args.time_units.get_unit())]; + if columns.cpu { + header.push("cpu".to_string()); + } + if columns.memory { + header.push(format!("memory_{}", args.mem_units.get_unit())); + } + if columns.disk { + header.push("disk_read".to_string()); + header.push("disk_write".to_string()); + } - reporter.write_to_report_file(&header); + report_file.write_all(format!("{}\n", header.join(",")).as_bytes())?; - Ok(Arc::new(reporter)) - } + while let Ok(row) = rx_write.recv() { + let mut line = vec![]; - pub fn write( - &self, - row: Row, - ) { - let mut line = vec![]; + line.push({ + match args.time_units { + crate::args::TimeUnits::S => format!("{:.3}", args.time_units.to_f64(row.time)), + crate::args::TimeUnits::Ms => format!("{}", row.time.as_millis()), + } + }); - line.push({ - match self.args.time_units { - crate::args::TimeUnits::S => format!("{:.3}", self.args.time_units.to_f64(row.time)), - crate::args::TimeUnits::Ms => format!("{}", row.time.as_millis()), - } - }); + if columns.cpu { + if let Some(cpu) = row.cpu { + line.push(format!("{}", cpu)); + } + } - if self.columns.cpu { - if let Some(cpu) = row.cpu { - line.push(format!("{}", cpu)); - } - } + if columns.memory { + if let Some(memory) = row.memory { + match args.mem_units { + MemoryUnits::Mb => { + line.push(format!("{}", memory / 1048576_u64)); + } + MemoryUnits::Kb => { + line.push(format!("{}", memory / 1024_u64)); + } + MemoryUnits::B => { + line.push(format!("{}", memory)); + } + } + } + } - if self.columns.memory { - if let Some(memory) = row.memory { - match self.args.mem_units { - MemoryUnits::Mb => { - line.push(format!("{}", memory / 1048576_u64)); + if columns.disk { + if let Some(disk_read) = row.disk_read { + line.push(format!("{}", disk_read)); } - MemoryUnits::Kb => { - line.push(format!("{}", memory / 1024_u64)); + if let Some(disk_write) = row.disk_write { + line.push(format!("{}", disk_write)); } - MemoryUnits::B => { - line.push(format!("{}", memory)); + } + + let mut output = String::new(); + for (i, col) in line.iter().enumerate() { + output.push_str(&col.to_string()); + if i != line.len() - 1 { + output.push(','); } } - } - } - if self.columns.disk { - if let Some(disk_read) = row.disk_read { - line.push(format!("{}", disk_read)); + report_file.write_all(format!("{}\n", output).as_bytes())?; } - if let Some(disk_write) = row.disk_write { - line.push(format!("{}", disk_write)); - } - } - self.rows.write().unwrap().push(row); - self.write_to_report_file(&line); + Ok(()) + }); + + Ok(Self { tx_writer }) } - fn write_to_report_file( + pub fn write( &self, - text: &[String], - ) { - let mut output = String::new(); - for (i, col) in text.iter().enumerate() { - output.push_str(&col.to_string()); - if i != text.len() - 1 { - output.push(','); - } - } - writeln!(&self.report_file, "{}", output).expect("Unable to write to file"); + row: Row, + ) -> anyhow::Result<()> { + Ok(self.tx_writer.send(row)?) } } diff --git a/x.sh b/x.sh deleted file mode 100644 index f40c5f7..0000000 --- a/x.sh +++ /dev/null @@ -1,8 +0,0 @@ -LAST_TAG=$(curl -sSL https://api.github.com/repos/alshdavid/procmon/releases/latest | jq ".tag_name" | cut -d "." -f 3) -if [ "$LAST_TAG" = "" ]; then - LAST_TAG="0" -fi -declare -i var="$LAST_TAG" -var=$var+1 -TAG="0.0.$var" -echo $TAG \ No newline at end of file