diff --git a/Cargo.lock b/Cargo.lock index 624c1c7..471e0ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,1186 +1,1215 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[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", ] [[package]] name = "ansi-str" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cf4578926a981ab0ca955dc023541d19de37112bc24c1a197bd806d3d86ad1d" dependencies = [ "ansitok", ] [[package]] name = "ansitok" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "220044e6a1bb31ddee4e3db724d29767f352de47445a6cd75e1a173142136c83" dependencies = [ "nom", "vte", ] [[package]] name = "anstream" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys", ] [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytecount" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" [[package]] name = "cc" version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856" dependencies = [ "libc", ] [[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.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", "windows-targets", ] [[package]] name = "clap" version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap-verbosity-flag" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5fdbb015d790cfb378aca82caf9cc52a38be96a7eecdb92f31b4366a8afc019" dependencies = [ "clap", "log", ] [[package]] name = "clap_builder" version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", "syn 2.0.39", ] [[package]] name = "clap_lex" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "codespan-reporting" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ "termcolor", "unicode-width", ] [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", "windows-sys", ] [[package]] name = "core-foundation-sys" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cxx" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" dependencies = [ "cc", "cxxbridge-flags", "cxxbridge-macro", "link-cplusplus", ] [[package]] name = "cxx-build" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" dependencies = [ "cc", "codespan-reporting", "once_cell", "proc-macro2", "quote", "scratch", "syn 2.0.39", ] [[package]] name = "cxxbridge-flags" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" [[package]] name = "cxxbridge-macro" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", "syn 2.0.39", ] [[package]] name = "darwin-libproc" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb90051930c9a0f09e585762152048e23ac74d20c10590ef7cf01c0343c3046" dependencies = [ "darwin-libproc-sys", "libc", "memchr", ] [[package]] name = "darwin-libproc-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57cebb5bde66eecdd30ddc4b9cd208238b15db4982ccc72db59d699ea10867c1" dependencies = [ "libc", ] [[package]] name = "derive_more" version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "env_logger" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", "log", "regex", "termcolor", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" dependencies = [ "libc", "windows-sys", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "global_placeholders" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d70af3f3fd800923fa445d6fa562e054d8abaf06df926f77dd6dbead1fefb275" dependencies = [ "parking_lot", ] [[package]] name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ "windows-sys", ] [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "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 = "indexmap" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is-terminal" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", "windows-sys", ] [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "link-cplusplus" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] [[package]] name = "linux-raw-sys" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "mach" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ "libc", ] [[package]] name = "macros-rs" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fb0c4278fff6f86cf9a14ed6c8e1a393d798587303418a5706dbec35f667946" [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nix" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ "bitflags 1.3.2", "cc", "cfg-if", "libc", "memoffset", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "papergrid" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8" dependencies = [ "ansi-str", "ansitok", "bytecount", "fnv", "unicode-width", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", "windows-targets", ] [[package]] name = "platforms" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "pmc" -version = "1.1.2" +version = "1.2.0" dependencies = [ "anyhow", "chrono", "clap", "clap-verbosity-flag", "colored", "cxx", "cxx-build", "env_logger", "global_placeholders", "home", "libc", "log", "macros-rs", "once_cell", "pretty_env_logger", "psutil", "regex", "serde", "serde_json", + "simple-logging", "tabled", "termcolor", "toml", ] [[package]] name = "pretty_env_logger" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ "env_logger", "log", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn 1.0.109", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "psutil" version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f866af2b0f8e4b0d2d00aad8a9c5fc48fad33466cd99a64cbb3a4c1505f1a62d" dependencies = [ "cfg-if", "darwin-libproc", "derive_more", "glob", "mach", "nix", "num_cpus", "once_cell", "platforms", "thiserror", "unescape", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustix" version = "0.38.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80109a168d9bc0c7f483083244543a6eb0dba02295d33ca268145e6190d6df0c" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "serde" version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", "syn 2.0.39", ] [[package]] name = "serde_json" version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] +[[package]] +name = "simple-logging" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00d48e85675326bb182a2286ea7c1a0b264333ae10f27a937a72be08628b542" +dependencies = [ + "lazy_static", + "log", + "thread-id", +] + [[package]] name = "smallvec" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tabled" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22" dependencies = [ "ansi-str", "ansitok", "papergrid", "tabled_derive", "unicode-width", ] [[package]] name = "tabled_derive" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" dependencies = [ "heck", "proc-macro-error", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "termcolor" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", "syn 2.0.39", ] +[[package]] +name = "thread-id" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" +dependencies = [ + "libc", + "redox_syscall 0.1.57", + "winapi", +] + [[package]] name = "toml" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "unescape" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vte" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" dependencies = [ "arrayvec", "utf8parse", "vte_generate_state_changes", ] [[package]] name = "vte_generate_state_changes" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "wasm-bindgen" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[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_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[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_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index ccdd87b..c109694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,34 +1,35 @@ [package] name = "pmc" -version = "1.1.2" +version = "1.2.0" edition = "2021" license = "MIT" repository = "https://lab.themackabu.dev/crates/pmc" description = "Process management controller" [dependencies] clap = "4.4.8" log = "0.4.20" toml = "0.8.8" home = "0.5.5" cxx = "1.0.110" psutil = "3.2.2" regex = "1.10.2" libc = "0.2.150" anyhow = "1.0.75" colored = "2.0.4" macros-rs = "0.4.2" termcolor = "1.4.0" once_cell = "1.18.0" env_logger = "0.10.1" serde_json = "1.0.108" +simple-logging = "2.0.2" pretty_env_logger = "0.5.0" clap-verbosity-flag = "2.1.0" global_placeholders = "0.1.0" tabled = { version = "0.14.0", features = ["color"] } chrono = { version = "0.4.23", features = ["serde"] } serde = { version = "1.0.192", features = ["derive"] } [build-dependencies] chrono = "0.4.23" cxx-build = "1.0.110" diff --git a/Maidfile.toml b/Maidfile.toml index 6a2563f..3bb4cff 100644 --- a/Maidfile.toml +++ b/Maidfile.toml @@ -1,24 +1,24 @@ [project] name = "pmc" -version = "1.1.2" +version = "1.2.0" [tasks] clean = { script = ["rm -rf bin", "mkdir bin"] } [tasks.build] depends = ["clean"] script = [ "cargo zigbuild --release", "cp target/release/pmc bin/pmc" ] [tasks.build.cache] path = "src" target = ["bin/pmc"] [tasks.install] script = [ "maid build -q", "sudo cp bin/pmc /usr/local/bin", "echo Copied binary!" ] diff --git a/src/daemon/log.rs b/src/daemon/log.rs new file mode 100644 index 0000000..7e7ad6c --- /dev/null +++ b/src/daemon/log.rs @@ -0,0 +1,17 @@ +use chrono::Local; +use global_placeholders::global; +use std::fs::{File, OpenOptions}; +use std::io::{self, Write}; + +pub struct Logger { + file: File, +} + +impl Logger { + pub fn new() -> io::Result<Self> { + let file = OpenOptions::new().create(true).append(true).open(global!("pmc.daemon.log"))?; + Ok(Logger { file }) + } + + pub fn write(&mut self, message: &str) { writeln!(&mut self.file, "[{}] {}", Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), message).unwrap() } +} diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index 2f49271..ae2ba99 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -1,217 +1,241 @@ -pub mod fork; +mod fork; +mod log; pub mod pid; use crate::config; -use crate::helpers::{self, ColoredString}; +use crate::file; +use crate::helpers::{self, ColoredString, Id}; use crate::process::Runner; use crate::service; use chrono::{DateTime, Utc}; use colored::Colorize; use fork::{daemon, Fork}; use global_placeholders::global; -use macros_rs::{crashln, string, ternary, then}; +use log::Logger; +use macros_rs::{crashln, str, string, ternary, then}; use psutil::process::{MemoryInfo, Process}; use serde::Serialize; use serde_json::json; use std::{process, thread::sleep, time::Duration}; use tabled::{ settings::{ object::Columns, style::{BorderColor, Style}, themes::Colorization, Color, Rotate, }, Table, Tabled, }; extern "C" fn handle_termination_signal(_: libc::c_int) { pid::remove(); + let mut log = Logger::new().unwrap(); + log.write(format!("daemon killed (pid={})", process::id()).as_str()); unsafe { libc::_exit(0) } } fn restart_process(runner: Runner) { + let mut log = Logger::new().unwrap(); let items = runner.list().iter().filter_map(|(id, item)| Some((id.trim().parse::<usize>().ok()?, item))); for (id, item) in items { then!(!item.running || pid::running(item.pid as i32), continue); let name = &Some(item.name.clone()); let mut runner_instance = Runner::new(); runner_instance.restart(id, name); + log.write(format!("restarted {} ({id})", item.name).as_str()); } } pub fn health(format: &String) { - let runner = Runner::new(); let mut pid: Option<i32> = None; let mut cpu_percent: Option<f32> = None; let mut uptime: Option<DateTime<Utc>> = None; let mut memory_usage: Option<MemoryInfo> = None; + let runner: Runner = file::read(global!("pmc.dump")); #[derive(Clone, Debug, Tabled)] struct Info { #[tabled(rename = "pid file")] pid_file: String, #[tabled(rename = "fork path")] path: String, #[tabled(rename = "cpu percent")] cpu_percent: String, #[tabled(rename = "memory usage")] memory_usage: String, #[tabled(rename = "daemon type")] external: String, #[tabled(rename = "process count")] process_count: usize, uptime: String, pid: String, status: ColoredString, } impl Serialize for Info { fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { let trimmed_json = json!({ "pid_file": &self.pid_file.trim(), "path": &self.path.trim(), "cpu": &self.cpu_percent.trim(), "mem": &self.memory_usage.trim(), "process_count": &self.process_count.to_string(), "uptime": &self.uptime.trim(), "pid": &self.pid.trim(), "status": &self.status.0.trim(), }); trimmed_json.serialize(serializer) } } if pid::exists() { if let Ok(process_id) = pid::read() { if let Ok(mut process) = Process::new(process_id as u32) { pid = Some(process_id); uptime = Some(pid::uptime().unwrap()); memory_usage = process.memory_info().ok(); cpu_percent = process.cpu_percent().ok(); } } } let cpu_percent = match cpu_percent { Some(percent) => format!("{:.2}%", percent), None => string!("0%"), }; let memory_usage = match memory_usage { Some(usage) => helpers::format_memory(usage.rss()), None => string!("0b"), }; let uptime = match uptime { Some(uptime) => helpers::format_duration(uptime), None => string!("none"), }; let pid = match pid { Some(pid) => string!(pid), None => string!("n/a"), }; let data = vec![Info { pid: pid, cpu_percent, memory_usage, uptime: uptime, path: global!("pmc.base"), external: global!("pmc.daemon.kind"), process_count: runner.list().keys().len(), pid_file: format!("{} ", global!("pmc.pid")), status: ColoredString(ternary!(pid::exists(), "online".green().bold(), "stopped".red().bold())), }]; let table = Table::new(data.clone()) .with(Rotate::Left) .with(Style::rounded().remove_horizontals()) .with(Colorization::exact([Color::FG_CYAN], Columns::first())) .with(BorderColor::filled(Color::FG_BRIGHT_BLACK)) .to_string(); if let Ok(json) = serde_json::to_string(&data[0]) { match format.as_str() { "raw" => println!("{:?}", data[0]), "json" => println!("{json}"), "default" => { println!("{}\n{table}\n", format!("PMC daemon information").on_bright_white().black()); println!(" {}", format!("Use `pmc daemon restart` to restart the daemon").white()); println!(" {}", format!("Use `pmc daemon reset` to clean process id values").white()); } _ => {} }; }; } pub fn stop() { if pid::exists() { + let mut log = Logger::new().unwrap(); println!("{} Stopping PMC daemon", *helpers::SUCCESS); match pid::read() { Ok(pid) => { service::stop(pid as i64); pid::remove(); + log.write(format!("daemon stopped (pid={pid})").as_str()); println!("{} PMC daemon stopped", *helpers::SUCCESS); } Err(err) => crashln!("{} Failed to read PID file: {}", *helpers::FAIL, err), } } else { crashln!("{} The daemon is not running", *helpers::FAIL) } } pub fn start() { let external = match global!("pmc.daemon.kind").as_str() { "external" => true, "default" => false, "rust" => false, "cc" => true, _ => false, }; pid::name("PMC Restart Handler Daemon"); println!("{} Spawning PMC daemon (pmc_base={})", *helpers::SUCCESS, global!("pmc.base")); if pid::exists() { match pid::read() { Ok(pid) => then!(!pid::running(pid), pid::remove()), Err(_) => crashln!("{} The daemon is already running", *helpers::FAIL), } } extern "C" fn init() { let config = config::read(); + let mut log = Logger::new().unwrap(); + unsafe { libc::signal(libc::SIGTERM, handle_termination_signal as usize) }; pid::write(process::id()); + log.write(format!("new daemon forked (pid={})", process::id()).as_str()); loop { - let runner = Runner::new(); + let runner: Runner = file::read(global!("pmc.dump")); then!(!runner.list().is_empty(), restart_process(runner)); sleep(Duration::from_millis(config.daemon.interval)); } } println!("{} PMC Successfully daemonized (type={})", *helpers::SUCCESS, global!("pmc.daemon.kind")); if external { let callback = crate::Callback(init); crate::service::try_fork(false, false, callback); } else { match daemon(false, false) { Ok(Fork::Parent(_)) => {} Ok(Fork::Child) => init(), Err(err) => crashln!("{} Daemon creation failed with code {err}", *helpers::FAIL), } } } pub fn restart() { if pid::exists() { stop(); } start(); } + +pub fn reset() { + let mut runner = Runner::new(); + let largest = runner.list().keys().last().cloned(); + + match largest { + Some(id) => runner.set_id(Id::from(str!(id))), + None => println!("{} Cannot reset index, no ID found", *helpers::FAIL), + } + + println!("{} PMC Successfully reset (index={})", *helpers::SUCCESS, runner.id); +} diff --git a/src/globals.rs b/src/globals.rs index 6d497c0..afb48e5 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,43 +1,40 @@ use crate::config; use crate::file::Exists; use crate::helpers; use global_placeholders::init; use macros_rs::crashln; use std::fs; pub fn init() { match home::home_dir() { Some(path) => { let path = path.display(); if !Exists::folder(format!("{path}/.pmc/")).unwrap() { fs::create_dir_all(format!("{path}/.pmc/")).unwrap(); log::info!("created pmc base dir"); } let config = config::read(); if !Exists::folder(config.runner.log_path.clone()).unwrap() { fs::create_dir_all(&config.runner.log_path).unwrap(); log::info!("created pmc log dir"); } init!("pmc.base", format!("{path}/.pmc/")); + init!("pmc.log", format!("{path}/.pmc/pmc.log")); init!("pmc.pid", format!("{path}/.pmc/daemon.pid")); init!("pmc.dump", format!("{path}/.pmc/process.dump")); - init!("pmc.config.shell", config.runner.shell); - init!("pmc.config.log_path", config.runner.log_path); - init!("pmc.daemon.kind", config.daemon.kind); - init!("pmc.daemon.interval", config.daemon.interval); - init!("pmc.daemon.logs", format!("{path}/.pmc/daemon.log")); + init!("pmc.daemon.log", format!("{path}/.pmc/daemon.log")); let out = format!("{}/{{}}-out.log", config.runner.log_path); let error = format!("{}/{{}}-error.log", config.runner.log_path); init!("pmc.logs.out", out); init!("pmc.logs.error", error); } None => crashln!("{} Impossible to get your home directory", *helpers::FAIL), } } diff --git a/src/helpers.rs b/src/helpers.rs index 1bfa342..ffdc53a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,61 +1,87 @@ use chrono::{DateTime, Utc}; use colored::Colorize; use core::fmt; use once_cell::sync::Lazy; use regex::Regex; use serde::{Deserialize, Serialize}; +use std::str::FromStr; use std::sync::atomic::{AtomicUsize, Ordering}; pub static SUCCESS: Lazy<colored::ColoredString> = Lazy::new(|| "[PMC]".green()); pub static FAIL: Lazy<colored::ColoredString> = Lazy::new(|| "[PMC]".red()); #[derive(Clone, Debug)] pub struct ColoredString(pub colored::ColoredString); impl serde::Serialize for ColoredString { fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { let re = Regex::new(r"\x1B\[([0-9;]+)m").unwrap(); let colored_string = &self.0; let stripped_string = re.replace_all(colored_string, "").to_string(); serializer.serialize_str(&stripped_string) } } impl fmt::Display for ColoredString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[derive(Debug, Deserialize, Serialize)] pub struct Id { pub counter: AtomicUsize, } impl Id { pub fn new(start: usize) -> Self { Id { counter: AtomicUsize::new(start) } } pub fn next(&self) -> usize { self.counter.fetch_add(1, Ordering::SeqCst) } } +impl FromStr for Id { + type Err = &'static str; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if let Ok(value) = s.parse::<usize>() { + Ok(Id::new(value)) + } else { + Err("Failed to parse string into usize") + } + } +} + +impl From<&str> for Id { + fn from(s: &str) -> Self { + match s.parse::<Id>() { + Ok(id) => id, + Err(_) => Id::new(0), + } + } +} + +impl fmt::Display for Id { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.counter.load(Ordering::SeqCst)) } +} + pub fn format_duration(datetime: DateTime<Utc>) -> String { let current_time = Utc::now(); let duration = current_time.signed_duration_since(datetime); match duration.num_seconds() { s if s >= 86400 => format!("{}d", s / 86400), s if s >= 3600 => format!("{}h", s / 3600), s if s >= 60 => format!("{}m", s / 60), s => format!("{}s", s), } } pub fn format_memory(bytes: u64) -> String { const KB: u64 = 1024; const MB: u64 = KB * 1024; const GB: u64 = MB * 1024; match bytes { 0..=KB if bytes < KB => format!("{}b", bytes), KB..=MB if bytes < MB => format!("{:.1}kb", bytes as f64 / KB as f64), MB..=GB if bytes < GB => format!("{:.1}mb", bytes as f64 / MB as f64), _ => format!("{:.1}gb", bytes as f64 / GB as f64), } } diff --git a/src/main.rs b/src/main.rs index 3ffc003..1d11969 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,173 +1,173 @@ mod cli; mod config; mod daemon; mod file; mod globals; mod helpers; mod process; mod structs; use crate::structs::Args; use clap::{Parser, Subcommand}; use clap_verbosity_flag::Verbosity; use cxx::{type_id, ExternType}; use macros_rs::{str, string, then}; fn validate_id_script(s: &str) -> Result<Args, String> { if let Ok(id) = s.parse::<usize>() { Ok(Args::Id(id)) } else { Ok(Args::Script(s.to_owned())) } } #[derive(Parser)] #[command(version = str!(cli::get_version(false)))] struct Cli { #[command(subcommand)] command: Commands, #[clap(flatten)] verbose: Verbosity, } #[derive(Subcommand)] enum Daemon { /// Reset process index #[command(alias = "clean")] Reset, /// Stop daemon #[command(alias = "kill")] Stop, /// Restart daemon #[command(alias = "restart", alias = "start")] Restore, /// Check daemon #[command(alias = "info")] Health { /// Format output #[arg(long, default_value_t = string!("default"))] format: String, }, } // add pmc restore command #[derive(Subcommand)] enum Commands { /// Start/Restart a process #[command(alias = "restart")] Start { #[arg(long, help = "process name")] name: Option<String>, #[clap(value_parser = validate_id_script)] args: Option<Args>, }, /// Stop/Kill a process #[command(alias = "kill")] Stop { id: usize }, /// Stop then remove a process #[command(alias = "rm")] Remove { id: usize }, /// Get env of a process #[command(alias = "cmdline")] Env { id: usize }, /// Get information of a process #[command(alias = "info")] Details { id: usize, /// Format output #[arg(long, default_value_t = string!("default"))] format: String, }, /// List all processes #[command(alias = "ls")] List { /// Format output #[arg(long, default_value_t = string!("default"))] format: String, }, /// Get logs from a process Logs { id: usize, #[arg(long, default_value_t = 15, help = "")] lines: usize, }, /// Daemon management Daemon { #[command(subcommand)] command: Daemon, }, } fn main() { globals::init(); let cli = Cli::parse(); let mut env = env_logger::Builder::new(); env.filter_level(cli.verbose.log_level_filter()).init(); match &cli.command { // add --watch Commands::Start { name, args } => cli::start(name, args), Commands::Stop { id } => cli::stop(id), Commands::Remove { id } => cli::remove(id), Commands::Env { id } => cli::env(id), Commands::Details { id, format } => cli::info(id, format), Commands::List { format } => cli::list(format), Commands::Logs { id, lines } => cli::logs(id, lines), Commands::Daemon { command } => match command { - Daemon::Reset => {} Daemon::Stop => daemon::stop(), + Daemon::Reset => daemon::reset(), Daemon::Restore => daemon::restart(), Daemon::Health { format } => daemon::health(format), }, }; if !matches!(&cli.command, Commands::Daemon { .. }) { then!(!daemon::pid::exists(), daemon::start()); } } #[repr(transparent)] pub struct Callback(pub extern "C" fn()); unsafe impl ExternType for Callback { type Id = type_id!("Callback"); type Kind = cxx::kind::Trivial; } #[cxx::bridge] pub mod service { #[repr(u8)] enum Fork { Parent, Child, } pub struct ProcessMetadata { pub name: String, pub shell: String, pub command: String, pub log_path: String, pub args: Vec<String>, } unsafe extern "C++" { include!("pmc/src/include/process.h"); include!("pmc/src/include/bridge.h"); include!("pmc/src/include/fork.h"); type Callback = crate::Callback; pub fn stop(pid: i64) -> i64; pub fn run(metadata: ProcessMetadata) -> i64; pub fn try_fork(nochdir: bool, noclose: bool, callback: Callback) -> i32; } } diff --git a/src/process/log.rs b/src/process/log.rs new file mode 100644 index 0000000..558cef3 --- /dev/null +++ b/src/process/log.rs @@ -0,0 +1,17 @@ +use chrono::Local; +use global_placeholders::global; +use std::fs::{File, OpenOptions}; +use std::io::{self, Write}; + +pub struct Logger { + file: File, +} + +impl Logger { + pub fn new() -> io::Result<Self> { + let file = OpenOptions::new().create(true).append(true).open(global!("pmc.log"))?; + Ok(Logger { file }) + } + + pub fn write(&mut self, message: &str) { writeln!(&mut self.file, "[{}] {}", Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), message).unwrap() } +} diff --git a/src/process/mod.rs b/src/process/mod.rs index 767e30d..0d7f65e 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -1,134 +1,142 @@ mod dump; +mod log; use crate::config; use crate::file; use crate::helpers::{self, Id}; use crate::service::{run, stop, ProcessMetadata}; use chrono::serde::ts_milliseconds; use chrono::{DateTime, Utc}; use macros_rs::{crashln, string}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; use std::env; use std::path::PathBuf; #[derive(Debug, Deserialize, Serialize)] pub struct Process { pub pid: i64, pub name: String, pub path: PathBuf, pub script: String, pub env: HashMap<String, String>, #[serde(with = "ts_milliseconds")] pub started: DateTime<Utc>, + // pub restarts: u64, pub running: bool, } #[derive(Debug, Deserialize, Serialize)] pub struct Runner { - id: Id, - process_list: BTreeMap<String, Process>, + pub id: Id, + pub process_list: BTreeMap<String, Process>, } impl Runner { pub fn new() -> Self { let dump = dump::read(); let runner = Runner { id: dump.id, process_list: dump.process_list, }; dump::write(&runner); return runner; } pub fn start(&mut self, name: &String, command: &String) { let config = config::read().runner; let pid = run(ProcessMetadata { name: name.clone(), log_path: config.log_path, command: command.clone(), shell: config.shell, args: config.args, }); self.process_list.insert( string!(self.id.next()), Process { pid, running: true, path: file::cwd(), name: name.clone(), started: Utc::now(), script: command.clone(), env: env::vars().collect(), }, ); dump::write(&self); } pub fn stop(&mut self, id: usize) { if let Some(item) = self.process_list.get_mut(&string!(id)) { stop(item.pid); item.running = false; dump::write(&self); } else { crashln!("{} Process ({id}) not found", *helpers::FAIL); } } pub fn restart(&mut self, id: usize, name: &Option<String>) { if let Some(item) = self.info(id) { let script = item.script.clone(); let path = item.path.clone(); let env = item.env.clone(); let name = match name { Some(name) => string!(name.trim()), None => string!(item.name.clone()), }; if let Err(err) = std::env::set_current_dir(&path) { crashln!("{} Failed to set working directory {:?}\nError: {:#?}", *helpers::FAIL, path, err); }; self.stop(id); let config = config::read().runner; let pid = run(ProcessMetadata { name: name.clone(), log_path: config.log_path, command: script.clone(), shell: config.shell, args: config.args, }); self.process_list.insert( string!(id), Process { pid, env, name, path, script, running: true, started: Utc::now(), }, ); dump::write(&self); } else { crashln!("{} Failed to restart process ({})", *helpers::FAIL, id); } } pub fn remove(&mut self, id: usize) { self.stop(id); self.process_list.remove(&string!(id)); dump::write(&self); } + pub fn set_id(&mut self, id: Id) { + self.id = id; + self.id.next(); + dump::write(&self); + } + pub fn info(&self, id: usize) -> Option<&Process> { self.process_list.get(&string!(id)) } pub fn list(&self) -> &BTreeMap<String, Process> { &self.process_list } }