gping-1.19.0/.cargo_vcs_info.json0000644000000001430000000000100122260ustar { "git": { "sha1": "e66b02167fa0cb2c5bae957e730d19ac9c22de47" }, "path_in_vcs": "gping" }gping-1.19.0/Cargo.lock0000644000001115650000000000100102140ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[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 = "anstream" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", "windows-sys 0.59.0", ] [[package]] name = "anyhow" version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cassowary" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "castaway" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" dependencies = [ "rustversion", ] [[package]] name = "cc" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] [[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.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets", ] [[package]] name = "clap" version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clap_mangen" version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbae9cbfdc5d4fa8711c09bd7b83f644cb48281ac35bf97af3e47b0675864bdf" dependencies = [ "clap", "roff", ] [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "compact_str" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" dependencies = [ "castaway", "cfg-if", "itoa", "rustversion", "ryu", "static_assertions", ] [[package]] name = "const_format" version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags", "crossterm_winapi", "mio", "parking_lot", "rustix", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "darling" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn", ] [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", "syn", ] [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[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.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "gping" version = "1.19.0" dependencies = [ "anyhow", "chrono", "clap", "clap_mangen", "const_format", "crossterm", "idna", "itertools", "pinger", "ratatui", "shadow-rs", ] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 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 = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indoc" version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "instability" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b829f37dead9dc39df40c2d3376c179fdfd2ac771f53f55d3c30dc096a3c0c6e" dependencies = [ "darling", "indoc", "pretty_assertions", "proc-macro2", "quote", "syn", ] [[package]] name = "is_debug" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8ea828c9d6638a5bd3d8b14e37502b4d56cae910ccf8a5b7f51c7a0eb1d0508" [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "lazy-regex" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" dependencies = [ "lazy-regex-proc_macros", "once_cell", "regex", ] [[package]] name = "lazy-regex-proc_macros" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" dependencies = [ "proc-macro2", "quote", "regex", "syn", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mio" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", "wasi", "windows-sys 0.52.0", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_threads" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pinger" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc53a927954d81a867bd7e9163a4b5f13babdf1627863d5b0ab52587fdb02ad" dependencies = [ "lazy-regex", "thiserror", "winping", ] [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "pretty_assertions" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ratatui" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ "bitflags", "cassowary", "compact_str", "crossterm", "indoc", "instability", "itertools", "lru", "paste", "strum", "unicode-segmentation", "unicode-truncate", "unicode-width 0.2.0", ] [[package]] name = "redox_syscall" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "roff" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" [[package]] name = "rustix" version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "rustversion" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "shadow-rs" version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "974eb8222c62a8588bc0f02794dd1ba5b60b3ec88b58e050729d0907ed6af610" dependencies = [ "const_format", "is_debug", "time", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", "syn", ] [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thiserror" version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "time" version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools", "unicode-segmentation", "unicode-width 0.1.14", ] [[package]] name = "unicode-width" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[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.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[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-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winapi_forked_icmpapi" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42aecb895d6340af9ccc8dab9aeabfeab6d5d7266c5fd172c8be7e07db71c1e3" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[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.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[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.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[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.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winping" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79ed0e3a789beb896b3de9fb7e93c76340f6f4adfab7770d6222b4b8625ef0aa" dependencies = [ "lazy_static", "static_assertions", "winapi_forked_icmpapi", ] [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn", ] gping-1.19.0/Cargo.toml0000644000000027520000000000100102340ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "gping" version = "1.19.0" authors = ["Tom Forbes "] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Ping, but with a graph." readme = "readme.md" license = "MIT" repository = "https://github.com/orf/gping" [[bin]] name = "gping" path = "src/main.rs" [dependencies.anyhow] version = "1.0.94" [dependencies.chrono] version = "0.4.39" [dependencies.clap] version = "4.5.23" features = ["derive"] [dependencies.clap_mangen] version = "0.2.24" [dependencies.const_format] version = "0.2.34" [dependencies.crossterm] version = "0.28.1" [dependencies.idna] version = "1.0.3" [dependencies.itertools] version = "0.13.0" [dependencies.pinger] version = "^2.0.0" [dependencies.shadow-rs] version = "0.37.0" default-features = false [dependencies.tui] version = "0.29.0" features = ["crossterm"] default-features = false package = "ratatui" [build-dependencies.shadow-rs] version = "0.37.0" default-features = false gping-1.19.0/Cargo.toml.orig000064400000000000000000000013611046102023000137100ustar 00000000000000[package] name = "gping" version = "1.19.0" authors = ["Tom Forbes "] edition = "2018" repository = "https://github.com/orf/gping" license = "MIT" description = "Ping, but with a graph." build = "build.rs" readme = "../readme.md" [dependencies] pinger = { version = "^2.0.0", path = "../pinger" } tui = { package = "ratatui", version = "0.29.0", features = ["crossterm"], default-features = false } crossterm = "0.28.1" anyhow = "1.0.94" chrono = "0.4.39" itertools = "0.13.0" shadow-rs = { version = "0.37.0", default-features = false } const_format = "0.2.34" clap = { version = "4.5.23", features = ["derive"] } clap_mangen = "0.2.24" idna = "1.0.3" [build-dependencies] shadow-rs = { version = "0.37.0", default-features = false } gping-1.19.0/build.rs000064400000000000000000000001101046102023000124550ustar 00000000000000fn main() { shadow_rs::ShadowBuilder::builder().build().unwrap(); } gping-1.19.0/readme.md000064400000000000000000000111661046102023000126040ustar 00000000000000# gping 🚀 [![Crates.io](https://img.shields.io/crates/v/gping.svg)](https://crates.io/crates/gping) [![Actions Status](https://github.com/orf/gping/workflows/CI/badge.svg)](https://github.com/orf/gping/actions) Ping, but with a graph. ![](./images/readme-example.gif) Comes with the following super-powers: * Graph the ping time for multiple hosts * Graph the _execution time_ for commands via the `--cmd` flag * Custom colours * Windows, Mac and Linux support Table of Contents ================= * [Install :cd:](#install-cd) * [Usage :saxophone:](#usage-saxophone) Packaging status # Install :cd: * macOS * [Homebrew](https://formulae.brew.sh/formula/gping#default): `brew install gping` * [MacPorts](https://ports.macports.org/port/gping/): `sudo port install gping` * Linux (Homebrew): `brew install gping` * CentOS (and other distributions with an old glibc): Download the MUSL build from the latest release * Windows/ARM: * Scoop: `scoop install gping` * Chocolatey: `choco install gping` * Download the latest release from [the github releases page](https://github.com/orf/gping/releases) * Fedora ([COPR](https://copr.fedorainfracloud.org/coprs/atim/gping/)): `sudo dnf copr enable atim/gping -y && sudo dnf install gping` * Cargo (**This requires `rustc` version 1.67.0 or greater**): `cargo install gping` * Arch Linux: `pacman -S gping` * Alpine linux: `apk add gping` * Ubuntu >23.10/Debian >13: `apt install gping` * Ubuntu/Debian ([Azlux's repo](https://packages.azlux.fr/)): ```bash echo 'deb [signed-by=/usr/share/keyrings/azlux.gpg] https://packages.azlux.fr/debian/ bookworm main' | sudo tee /etc/apt/sources.list.d/azlux.list sudo apt install gpg curl -s https://azlux.fr/repo.gpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/azlux.gpg > /dev/null sudo apt update sudo apt install gping ``` * Gentoo ([dm9pZCAq overlay](https://github.com/gentoo-mirror/dm9pZCAq)): ```sh sudo eselect repository enable dm9pZCAq sudo emerge --sync dm9pZCAq sudo emerge net-misc/gping::dm9pZCAq ``` * FreeBSD: * [pkg](https://www.freshports.org/net-mgmt/gping/): `pkg install gping` * [ports](https://cgit.freebsd.org/ports/tree/net-mgmt/gping) `cd /usr/ports/net-mgmt/gping; make install clean` * Docker: ```sh # Check all options docker run --rm -ti --network host ghcr.io/orf/gping:gping-v1.15.1 --help # Ping google.com docker run --rm -ti --network host ghcr.io/orf/gping:gping-v1.15.1 google.com ``` * Flox: ```sh # Inside of a Flox environment flox install gping ``` # Usage :saxophone: Just run `gping [host]`. `host` can be a command like `curl google.com` if the `--cmd` flag is used. You can also use shorthands like `aws:eu-west-1` or `aws:ca-central-1` to ping specific cloud regions. Only `aws` is currently supported. ```bash $ gping --help Ping, but with a graph. Usage: gping [OPTIONS] [HOSTS_OR_COMMANDS]... Arguments: [HOSTS_OR_COMMANDS]... Hosts or IPs to ping, or commands to run if --cmd is provided. Can use cloud shorthands like aws:eu-west-1. Options: --cmd Graph the execution time for a list of commands rather than pinging hosts -n, --watch-interval Watch interval seconds (provide partial seconds like '0.5'). Default for ping is 0.2, default for cmd is 0.5. -b, --buffer Determines the number of seconds to display in the graph. [default: 30] -4 Resolve ping targets to IPv4 address -6 Resolve ping targets to IPv6 address -i, --interface Interface to use when pinging -s, --simple-graphics Uses dot characters instead of braille --vertical-margin Vertical margin around the graph (top and bottom) [default: 1] --horizontal-margin Horizontal margin around the graph (left and right) [default: 0] -c, --color Assign color to a graph entry. This option can be defined more than once as a comma separated string, and the order which the colors are provided will be matched against the hosts or commands passed to gping. Hexadecimal RGB color codes are accepted in the form of '#RRGGBB' or the following color names: 'black', 'red', 'green', 'yellow', 'blue', 'magenta','cyan', 'gray', 'dark-gray', 'light-red', 'light-green', 'light-yellow', 'light-blue', 'light-magenta', 'light-cyan', and 'white' -h, --help Print help information -V, --version Print version information --clear Clear the graph from the terminal after closing the program ``` gping-1.19.0/src/colors.rs000064400000000000000000000026111046102023000134560ustar 00000000000000use std::{iter::Iterator, ops::RangeFrom, str::FromStr}; use anyhow::{anyhow, Result}; use tui::style::Color; pub struct Colors { already_used: Vec, color_names: T, indices: RangeFrom, } impl From for Colors { fn from(color_names: T) -> Self { Self { already_used: Vec::new(), color_names, indices: 2.., } } } impl<'a, T> Iterator for Colors where T: Iterator, { type Item = Result; fn next(&mut self) -> Option { match self.color_names.next() { Some(name) => match Color::from_str(name) { Ok(color) => { if !self.already_used.contains(&color) { self.already_used.push(color); } Some(Ok(color)) } error => Some(error.map_err(|err| { anyhow!(err).context(format!("Invalid color code: `{}`", name)) })), }, None => loop { let index = unsafe { self.indices.next().unwrap_unchecked() }; let color = Color::Indexed(index); if !self.already_used.contains(&color) { self.already_used.push(color); break Some(Ok(color)); } }, } } } gping-1.19.0/src/main.rs000064400000000000000000000500071046102023000131030ustar 00000000000000use crate::plot_data::PlotData; use anyhow::{anyhow, bail, Context, Result}; use chrono::prelude::*; use clap::{CommandFactory, Parser}; use crossterm::event::KeyModifiers; use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen}; use crossterm::{ event::{self, Event as CEvent, KeyCode}, execute, terminal::{disable_raw_mode, enable_raw_mode, SetSize}, }; use itertools::{Itertools, MinMaxResult}; use pinger::{ping, PingOptions, PingResult}; use std::io; use std::io::BufWriter; use std::iter; use std::net::{IpAddr, ToSocketAddrs}; use std::ops::Add; use std::path::Path; use std::process::{Command, ExitStatus, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::Sender; use std::sync::{mpsc, Arc}; use std::thread; use std::thread::{sleep, JoinHandle}; use std::time::{Duration, Instant}; use tui::backend::{Backend, CrosstermBackend}; use tui::layout::{Constraint, Direction, Flex, Layout}; use tui::style::{Color, Style}; use tui::text::Span; use tui::widgets::{Axis, Block, Borders, Chart, Dataset}; use tui::Terminal; mod colors; mod plot_data; mod region_map; use colors::Colors; use shadow_rs::{formatcp, shadow}; use tui::prelude::Position; shadow!(build); const VERSION_INFO: &str = formatcp!( r#"{} commit_hash: {} build_time: {} build_env: {},{}"#, build::PKG_VERSION, build::SHORT_COMMIT, build::BUILD_TIME, build::RUST_VERSION, build::RUST_CHANNEL ); #[derive(Parser, Debug)] #[command(author, version=build::PKG_VERSION, name = "gping", about = "Ping, but with a graph.", long_version = VERSION_INFO )] struct Args { /// Graph the execution time for a list of commands rather than pinging hosts #[arg(long)] cmd: bool, /// Watch interval seconds (provide partial seconds like '0.5'). Default for ping is 0.2, default for cmd is 0.5. #[arg(short = 'n', long)] watch_interval: Option, /// Hosts or IPs to ping, or commands to run if --cmd is provided. Can use cloud shorthands like aws:eu-west-1. #[arg(allow_hyphen_values = false)] hosts_or_commands: Vec, /// Determines the number of seconds to display in the graph. #[arg(short, long, default_value = "30")] buffer: u64, /// Resolve ping targets to IPv4 address #[arg(short = '4', conflicts_with = "ipv6")] ipv4: bool, /// Resolve ping targets to IPv6 address #[arg(short = '6', conflicts_with = "ipv4")] ipv6: bool, #[cfg(not(target_os = "windows"))] /// Interface to use when pinging. #[arg(short = 'i', long)] interface: Option, /// Uses dot characters instead of braille #[arg(short = 's', long, help = "")] simple_graphics: bool, /// Vertical margin around the graph (top and bottom) #[arg(long, default_value = "1")] vertical_margin: u16, /// Horizontal margin around the graph (left and right) #[arg(long, default_value = "0")] horizontal_margin: u16, #[arg( name = "color", short = 'c', long = "color", use_value_delimiter = true, value_delimiter = ',', help = r#"Assign color to a graph entry. This option can be defined more than once as a comma separated string, and the order which the colors are provided will be matched against the hosts or commands passed to gping. Hexadecimal RGB color codes are accepted in the form of '#RRGGBB' or the following color names: 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'gray', 'dark-gray', 'light-red', 'light-green', 'light-yellow', 'light-blue', 'light-magenta', 'light-cyan', and 'white'"# )] color_codes_or_names: Vec, /// Clear the graph from the terminal after closing the program #[arg(name = "clear", long = "clear", action)] clear: bool, #[cfg(not(target_os = "windows"))] /// Extra arguments to pass to `ping`. These are platform dependent. #[arg(long, allow_hyphen_values = true, num_args = 0.., conflicts_with="cmd")] ping_args: Option>, } struct App { data: Vec, display_interval: chrono::Duration, started: chrono::DateTime, } impl App { fn new(data: Vec, buffer: u64) -> Self { App { data, display_interval: chrono::Duration::from_std(Duration::from_secs(buffer)).unwrap(), started: Local::now(), } } fn update(&mut self, host_idx: usize, item: Option) { let host = &mut self.data[host_idx]; host.update(item); } fn y_axis_bounds(&self) -> [f64; 2] { // Find the Y axis bounds for our chart. // This is trickier than the x-axis. We iterate through all our PlotData structs // and find the min/max of all the values. Then we add a 10% buffer to them. let (min, max) = match self .data .iter() .flat_map(|b| b.data.as_slice()) .map(|v| v.1) .filter(|v| !v.is_nan()) .minmax() { MinMaxResult::NoElements => (f64::INFINITY, 0_f64), MinMaxResult::OneElement(elm) => (elm, elm), MinMaxResult::MinMax(min, max) => (min, max), }; // Add a 10% buffer to the top and bottom let max_10_percent = (max * 10_f64) / 100_f64; let min_10_percent = (min * 10_f64) / 100_f64; [min - min_10_percent, max + max_10_percent] } fn x_axis_bounds(&self) -> [f64; 2] { let now = Local::now(); let now_idx; let before_idx; if (now - self.started) < self.display_interval { now_idx = (self.started + self.display_interval).timestamp_millis() as f64 / 1_000f64; before_idx = self.started.timestamp_millis() as f64 / 1_000f64; } else { now_idx = now.timestamp_millis() as f64 / 1_000f64; let before = now - self.display_interval; before_idx = before.timestamp_millis() as f64 / 1_000f64; } [before_idx, now_idx] } fn x_axis_labels(&self, bounds: [f64; 2]) -> Vec { let lower_utc = DateTime::::from_timestamp(bounds[0] as i64, 0) .expect("Error parsing x-axis bounds 0"); let upper_utc = DateTime::::from_timestamp(bounds[1] as i64, 0) .expect("Error parsing x-asis bounds 1"); let lower: DateTime = DateTime::from(lower_utc); let upper: DateTime = DateTime::from(upper_utc); let diff = (upper - lower) / 2; let midpoint = lower + diff; vec![ Span::raw(format!("{:?}", lower.time())), Span::raw(format!("{:?}", midpoint.time())), Span::raw(format!("{:?}", upper.time())), ] } fn y_axis_labels(&self, bounds: [f64; 2]) -> Vec { // Create 7 labels for our y axis, based on the y-axis bounds we computed above. let min = bounds[0]; let max = bounds[1]; let difference = max - min; let num_labels = 7; // Split difference into one chunk for each of the 7 labels let increment = Duration::from_micros((difference / num_labels as f64) as u64); let duration = Duration::from_micros(min as u64); (0..num_labels) .map(|i| Span::raw(format!("{:?}", duration.add(increment * i)))) .collect() } } #[derive(Debug)] enum Update { Result(Duration), Timeout, Unknown, Terminated(ExitStatus, String), } impl From for Update { fn from(result: PingResult) -> Self { match result { PingResult::Pong(duration, _) => Update::Result(duration), PingResult::Timeout(_) => Update::Timeout, PingResult::Unknown(_) => Update::Unknown, PingResult::PingExited(e, stderr) => Update::Terminated(e, stderr), } } } #[derive(Debug)] enum Event { Update(usize, Update), Terminate, Render, } fn start_render_thread( kill_event: Arc, cmd_tx: Sender, ) -> JoinHandle> { thread::spawn(move || { while !kill_event.load(Ordering::Acquire) { sleep(Duration::from_millis(250)); cmd_tx.send(Event::Render)?; } Ok(()) }) } fn start_cmd_thread( watch_cmd: &str, host_id: usize, watch_interval: Option, cmd_tx: Sender, kill_event: Arc, ) -> JoinHandle> { let mut words = watch_cmd.split_ascii_whitespace(); let cmd = words .next() .expect("Must specify a command to watch") .to_string(); let cmd_args = words.map(|w| w.to_string()).collect::>(); let interval = Duration::from_millis((watch_interval.unwrap_or(0.5) * 1000.0) as u64); // Pump cmd watches into the queue thread::spawn(move || -> Result<()> { while !kill_event.load(Ordering::Acquire) { let start = Instant::now(); let mut child = Command::new(&cmd) .args(&cmd_args) .stderr(Stdio::null()) .stdout(Stdio::null()) .spawn()?; let status = child.wait()?; let duration = start.elapsed(); let update = if status.success() { Update::Result(duration) } else { Update::Timeout }; cmd_tx.send(Event::Update(host_id, update))?; sleep(interval); } Ok(()) }) } fn start_ping_thread( options: PingOptions, host_id: usize, ping_tx: Sender, kill_event: Arc, ) -> Result>> { let stream = ping(options)?; // Pump ping messages into the queue Ok(thread::spawn(move || -> Result<()> { while !kill_event.load(Ordering::Acquire) { match stream.recv() { Ok(v) => { ping_tx.send(Event::Update(host_id, v.into()))?; } Err(_) => { // Stream closed, just break return Ok(()); } } } Ok(()) })) } fn get_host_ipaddr(host: &str, force_ipv4: bool, force_ipv6: bool) -> Result { let mut host = host.to_string(); if !host.is_ascii() { let Ok(encoded_host) = idna::domain_to_ascii(&host) else { bail!("Could not encode host {host} to punycode") }; host = encoded_host; } let ipaddr: Vec<_> = (host.as_str(), 80) .to_socket_addrs() .with_context(|| format!("Resolving {host}"))? .map(|s| s.ip()) .collect(); if ipaddr.is_empty() { bail!("Could not resolve hostname {}", host) } let ipaddr = if force_ipv4 { ipaddr .iter() .find(|ip| matches!(ip, IpAddr::V4(_))) .ok_or_else(|| anyhow!("Could not resolve '{}' to IPv4", host)) } else if force_ipv6 { ipaddr .iter() .find(|ip| matches!(ip, IpAddr::V6(_))) .ok_or_else(|| anyhow!("Could not resolve '{}' to IPv6", host)) } else { ipaddr .first() .ok_or_else(|| anyhow!("Could not resolve '{}' to IP", host)) }; Ok(ipaddr?.to_string()) } fn generate_man_page(path: &Path) -> anyhow::Result<()> { let man = clap_mangen::Man::new(Args::command().version(None).long_version(None)); let mut buffer: Vec = Default::default(); man.render(&mut buffer)?; std::fs::write(path, buffer)?; Ok(()) } fn main() -> Result<()> { if let Some(path) = std::env::var_os("GENERATE_MANPAGE") { return generate_man_page(Path::new(&path)); }; let args: Args = Args::parse(); if args.hosts_or_commands.is_empty() { return Err(anyhow!("At least one host or command must be given (i.e gping google.com). Use --help for a full list of arguments.")); } let mut data = vec![]; let colors = Colors::from(args.color_codes_or_names.iter()); let hosts_or_commands: Vec = args .hosts_or_commands .clone() .into_iter() .map(|s| match region_map::try_host_from_cloud_region(&s) { None => s, Some(new_domain) => new_domain, }) .collect(); for (host_or_cmd, color) in hosts_or_commands.iter().zip(colors) { let color = color?; let display = match args.cmd { true => host_or_cmd.to_string(), false => format!( "{} ({})", host_or_cmd, get_host_ipaddr(host_or_cmd, args.ipv4, args.ipv6)? ), }; data.push(PlotData::new( display, args.buffer, Style::default().fg(color), args.simple_graphics, )); } #[cfg(not(target_os = "windows"))] let interface: Option = args.interface.clone(); #[cfg(target_os = "windows")] let interface: Option = None; #[cfg(not(target_os = "windows"))] let ping_args: Option> = args.ping_args.clone(); #[cfg(target_os = "windows")] let ping_args: Option> = None; let (key_tx, rx) = mpsc::channel(); let mut threads = vec![]; let killed = Arc::new(AtomicBool::new(false)); for (host_id, host_or_cmd) in hosts_or_commands.iter().cloned().enumerate() { if args.cmd { let cmd_thread = start_cmd_thread( &host_or_cmd, host_id, args.watch_interval, key_tx.clone(), std::sync::Arc::clone(&killed), ); threads.push(cmd_thread); } else { let interval = Duration::from_millis((args.watch_interval.unwrap_or(0.2) * 1000.0) as u64); let mut ping_opts = if args.ipv4 { PingOptions::new_ipv4(host_or_cmd, interval, interface.clone()) } else if args.ipv6 { PingOptions::new_ipv6(host_or_cmd, interval, interface.clone()) } else { PingOptions::new(host_or_cmd, interval, interface.clone()) }; if let Some(ping_args) = &ping_args { ping_opts = ping_opts.with_raw_arguments(ping_args.clone()); } threads.push(start_ping_thread( ping_opts, host_id, key_tx.clone(), std::sync::Arc::clone(&killed), )?); } } threads.push(start_render_thread( std::sync::Arc::clone(&killed), key_tx.clone(), )); let mut app = App::new(data, args.buffer); enable_raw_mode()?; let stdout = io::stdout(); let mut backend = CrosstermBackend::new(BufWriter::with_capacity(1024 * 1024 * 4, stdout)); let rect = backend.size()?; if args.clear { execute!( backend, SetSize(rect.width, rect.height), EnterAlternateScreen, )?; } else { execute!(backend, SetSize(rect.width, rect.height),)?; } let mut terminal = Terminal::new(backend)?; terminal.clear()?; // Pump keyboard messages into the queue let killed_thread = std::sync::Arc::clone(&killed); thread::spawn(move || -> Result<()> { while !killed_thread.load(Ordering::Acquire) { if event::poll(Duration::from_secs(5))? { if let CEvent::Key(key) = event::read()? { match key.code { KeyCode::Char('q') | KeyCode::Esc => { key_tx.send(Event::Terminate)?; break; } KeyCode::Char('c') if key.modifiers == KeyModifiers::CONTROL => { key_tx.send(Event::Terminate)?; break; } _ => {} } } } } Ok(()) }); loop { match rx.recv()? { Event::Update(host_id, update) => { match update { Update::Result(duration) => app.update(host_id, Some(duration)), Update::Timeout => app.update(host_id, None), Update::Unknown => (), Update::Terminated(e, _) if e.success() => { break; } Update::Terminated(e, stderr) => { eprintln!("There was an error running ping: {e}\nStderr: {stderr}\n"); break; } }; } Event::Render => { terminal.draw(|f| { let chunks = Layout::default() .flex(Flex::Legacy) .direction(Direction::Vertical) .vertical_margin(args.vertical_margin) .horizontal_margin(args.horizontal_margin) .constraints( iter::repeat(Constraint::Length(1)) .take(app.data.len()) .chain(iter::once(Constraint::Percentage(10))) .collect::>(), ) .split(f.area()); let total_chunks = chunks.len(); let header_chunks = &chunks[0..total_chunks - 1]; let chart_chunk = &chunks[total_chunks - 1]; for (plot_data, chunk) in app.data.iter().zip(header_chunks) { let header_layout = Layout::default() .direction(Direction::Horizontal) .constraints( [ Constraint::Percentage(30), Constraint::Percentage(10), Constraint::Percentage(10), Constraint::Percentage(10), Constraint::Percentage(10), Constraint::Percentage(10), Constraint::Percentage(10), Constraint::Percentage(10), ] .as_ref(), ) .split(*chunk); for (area, paragraph) in header_layout.iter().zip(plot_data.header_stats()) { f.render_widget(paragraph, *area); } } let datasets: Vec = app.data.iter().map(|d| d.into()).collect(); let y_axis_bounds = app.y_axis_bounds(); let x_axis_bounds = app.x_axis_bounds(); let chart = Chart::new(datasets) .block(Block::default().borders(Borders::NONE)) .x_axis( Axis::default() .style(Style::default().fg(Color::Gray)) .bounds(x_axis_bounds) .labels(app.x_axis_labels(x_axis_bounds)), ) .y_axis( Axis::default() .style(Style::default().fg(Color::Gray)) .bounds(y_axis_bounds) .labels(app.y_axis_labels(y_axis_bounds)), ); f.render_widget(chart, *chart_chunk) })?; } Event::Terminate => { killed.store(true, Ordering::Release); break; } } } killed.store(true, Ordering::Relaxed); disable_raw_mode()?; execute!(terminal.backend_mut())?; terminal.show_cursor()?; let new_size = terminal.size()?; terminal.set_cursor_position(Position { x: new_size.width, y: new_size.height, })?; for thread in threads { thread.join().unwrap()?; } if args.clear { execute!(terminal.backend_mut(), LeaveAlternateScreen)?; }; Ok(()) } gping-1.19.0/src/plot_data.rs000064400000000000000000000077731046102023000141420ustar 00000000000000use anyhow::Context; use chrono::prelude::*; use core::option::Option; use core::option::Option::{None, Some}; use core::time::Duration; use itertools::Itertools; use tui::style::Style; use tui::symbols; use tui::widgets::{Dataset, GraphType, Paragraph}; pub struct PlotData { pub display: String, pub data: Vec<(f64, f64)>, pub style: Style, buffer: chrono::Duration, simple_graphics: bool, } impl PlotData { pub fn new(display: String, buffer: u64, style: Style, simple_graphics: bool) -> PlotData { PlotData { display, data: Vec::with_capacity(150), style, buffer: chrono::Duration::try_seconds(buffer as i64) .with_context(|| format!("Error converting {buffer} to seconds")) .unwrap(), simple_graphics, } } pub fn update(&mut self, item: Option) { let now = Local::now(); let idx = now.timestamp_millis() as f64 / 1_000f64; match item { Some(dur) => self.data.push((idx, dur.as_micros() as f64)), None => self.data.push((idx, f64::NAN)), } // Find the last index that we should remove. let earliest_timestamp = (now - self.buffer).timestamp_millis() as f64 / 1_000f64; let last_idx = self .data .iter() .enumerate() .filter(|(_, (timestamp, _))| *timestamp < earliest_timestamp) .map(|(idx, _)| idx) .last(); if let Some(idx) = last_idx { self.data.drain(0..idx).for_each(drop) } } pub fn header_stats(&self) -> Vec { let ping_header = Paragraph::new(self.display.clone()).style(self.style); let items: Vec<&f64> = self .data .iter() .filter(|(_, x)| !x.is_nan()) .map(|(_, v)| v) .sorted_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) .collect(); if items.is_empty() { return vec![ping_header]; } let min = **items.first().unwrap(); let max = **items.last().unwrap(); let avg = items.iter().copied().sum::() / items.len() as f64; let jtr = items .iter() .zip(items.iter().skip(1)) .map(|(&prev, &curr)| (curr - prev).abs()) .sum::() / (items.len() - 1) as f64; let percentile_position = 0.95 * items.len() as f32; let rounded_position = percentile_position.round() as usize; let p95 = items.get(rounded_position).map(|i| **i).unwrap_or(0f64); // count timeouts let to = self.data.iter().filter(|(_, x)| x.is_nan()).count(); let last = self.data.last().unwrap_or(&(0f64, 0f64)).1; vec![ ping_header, Paragraph::new(format!("last {:?}", Duration::from_micros(last as u64))) .style(self.style), Paragraph::new(format!("min {:?}", Duration::from_micros(min as u64))) .style(self.style), Paragraph::new(format!("max {:?}", Duration::from_micros(max as u64))) .style(self.style), Paragraph::new(format!("avg {:?}", Duration::from_micros(avg as u64))) .style(self.style), Paragraph::new(format!("jtr {:?}", Duration::from_micros(jtr as u64))) .style(self.style), Paragraph::new(format!("p95 {:?}", Duration::from_micros(p95 as u64))) .style(self.style), Paragraph::new(format!("t/o {to:?}")).style(self.style), ] } } impl<'a> From<&'a PlotData> for Dataset<'a> { fn from(plot: &'a PlotData) -> Self { let slice = plot.data.as_slice(); Dataset::default() .marker(if plot.simple_graphics { symbols::Marker::Dot } else { symbols::Marker::Braille }) .style(plot.style) .graph_type(GraphType::Line) .data(slice) } } gping-1.19.0/src/region_map.rs000064400000000000000000000022401046102023000142730ustar 00000000000000type Host = String; pub fn try_host_from_cloud_region(query: &str) -> Option { match query.split_once(':') { Some(("aws", region)) => Some(format!("ec2.{region}.amazonaws.com")), Some(("gcp", "")) => Some("cloud.google.com".to_string()), Some(("gcp", region)) => Some(format!("storage.{region}.rep.googleapis.com")), _ => None, } } #[cfg(test)] mod tests { use super::*; #[test] fn test_host_from_aws() { assert_eq!( try_host_from_cloud_region("aws:eu-west-1"), Some("ec2.eu-west-1.amazonaws.com".to_string()) ); } #[test] fn test_host_from_gcp() { assert_eq!( try_host_from_cloud_region("gcp:me-central2"), Some("storage.me-central2.rep.googleapis.com".to_string()) ); assert_eq!( try_host_from_cloud_region("gcp:"), Some("cloud.google.com".to_string()) ); } #[test] fn test_host_from_foo() { assert_eq!(try_host_from_cloud_region("foo:bar"), None); } #[test] fn test_invalid_input() { assert_eq!(try_host_from_cloud_region("foo"), None); } }