├── .gitignore ├── .github └── dependabot.yml ├── .editorconfig ├── .pre-commit-config.yaml ├── ci ├── script.sh ├── before_deploy.ps1 ├── before_deploy.sh └── install.sh ├── Cargo.toml ├── LICENSE.MIT.md ├── CHANGELOG.md ├── src ├── cli.yml └── main.rs ├── .appveyor.yml ├── README.md ├── .travis.yml ├── LICENSE.Apache-2.0.txt └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "00:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.rs] 12 | indent_size = 4 13 | 14 | # clap's YAML support requires using 4-space indentation 15 | [src/cli.yml] 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v3.3.0 4 | hooks: 5 | - id: fix-byte-order-marker 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | 9 | - id: mixed-line-ending 10 | args: [--fix=lf] 11 | 12 | - repo: https://github.com/doublify/pre-commit-rust 13 | rev: v1.0 14 | hooks: 15 | - id: fmt 16 | -------------------------------------------------------------------------------- /ci/script.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of testing your crate 2 | 3 | set -ex 4 | 5 | main() { 6 | cross build --target $TARGET 7 | cross build --target $TARGET --release 8 | 9 | if [ ! -z $DISABLE_TESTS ]; then 10 | return 11 | fi 12 | 13 | cross test --target $TARGET 14 | cross test --target $TARGET --release 15 | 16 | # cross run --target $TARGET 17 | # cross run --target $TARGET --release 18 | } 19 | 20 | # we don't run the "test phase" when doing deploys 21 | if [ -z $TRAVIS_TAG ]; then 22 | main 23 | fi 24 | -------------------------------------------------------------------------------- /ci/before_deploy.ps1: -------------------------------------------------------------------------------- 1 | # This script takes care of packaging the build artifacts that will go in the 2 | # release zipfile 3 | 4 | $SRC_DIR = $PWD.Path 5 | $STAGE = [System.Guid]::NewGuid().ToString() 6 | 7 | Set-Location $ENV:Temp 8 | New-Item -Type Directory -Name $STAGE 9 | Set-Location $STAGE 10 | 11 | $ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip" 12 | 13 | Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\lagraph.exe" '.\' 14 | 15 | 7z a "$ZIP" * 16 | 17 | Push-AppveyorArtifact "$ZIP" 18 | 19 | Remove-Item *.* -Force 20 | Set-Location .. 21 | Remove-Item $STAGE 22 | Set-Location $SRC_DIR 23 | -------------------------------------------------------------------------------- /ci/before_deploy.sh: -------------------------------------------------------------------------------- 1 | # This script takes care of building your crate and packaging it for release 2 | 3 | set -ex 4 | 5 | main() { 6 | local src=$(pwd) \ 7 | stage= 8 | 9 | case $TRAVIS_OS_NAME in 10 | linux) 11 | stage=$(mktemp -d) 12 | ;; 13 | osx) 14 | stage=$(mktemp -d -t tmp) 15 | ;; 16 | esac 17 | 18 | test -f Cargo.lock || cargo generate-lockfile 19 | 20 | cross rustc --bin $CRATE_NAME --target $TARGET --release -- -C lto 21 | 22 | cp target/$TARGET/release/$CRATE_NAME $stage/ || cp target/$TARGET/release/$CRATE_NAME.exe $stage/ 23 | 24 | cd $stage 25 | tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz * 26 | cd $src 27 | 28 | rm -rf $stage 29 | } 30 | 31 | main 32 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lagraph" 3 | version = "0.2.1" 4 | description = "Display a ping graph in a terminal" 5 | authors = ["Hugo Locurcio "] 6 | license = "MIT/Apache-2.0" 7 | keywords = ["ping", "latency", "network", "graph", "cli"] 8 | repository = "https://github.com/Calinou/lagraph" 9 | categories = ["command-line-interface"] 10 | readme = "README.md" 11 | edition = "2018" 12 | 13 | [badges] 14 | appveyor = { repository = "https://github.com/Calinou/lagraph" } 15 | travis-ci = { repository = "Calinou/lagraph" } 16 | is-it-maintained-issue-resolution = { repository = "https://github.com/Calinou/lagraph" } 17 | is-it-maintained-open-issues = { repository = "https://github.com/Calinou/lagraph" } 18 | maintenance = { status = "passively-maintained" } 19 | 20 | [profile.release] 21 | lto = true 22 | 23 | [dependencies] 24 | ansi_term = "0.12.1" 25 | chrono = "0.4.23" 26 | terminal_size = "0.2.5" 27 | 28 | [dependencies.clap] 29 | version = "3.2.23" 30 | features = ["yaml"] 31 | -------------------------------------------------------------------------------- /LICENSE.MIT.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright © 2018-2019 Hugo Locurcio and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.2.1] - 2018-09-01 11 | 12 | ### Changed 13 | 14 | - The ping value is now right-aligned. 15 | 16 | ### Fixed 17 | 18 | - `ping` command output is now correctly parsed on Windows in languages 19 | other than English. 20 | 21 | ## [0.2.0] - 2018-08-23 22 | 23 | ### Added 24 | 25 | - Windows support. 26 | - Binary releases compiled using [trust](https://github.com/japaric/trust) 27 | are now available on the Releases page. 28 | 29 | ### Changed 30 | 31 | - Release binaries are now built with link-time optimization enabled, 32 | resulting in smaller file sizes. 33 | 34 | ### Fixed 35 | 36 | - The `COLORTERM` environment variable is now properly taken into account 37 | at run-time. 38 | 39 | ## 0.1.0 - 2018-08-21 40 | 41 | - Initial versioned release. 42 | 43 | [Unreleased]: https://github.com/Calinou/lagraph/compare/v0.2.1...HEAD 44 | [0.2.1]: https://github.com/Calinou/lagraph/compare/v0.2.0...v0.2.1 45 | [0.2.0]: https://github.com/Calinou/lagraph/compare/v0.1.0...v0.2.0 46 | -------------------------------------------------------------------------------- /ci/install.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | main() { 4 | local target= 5 | if [ $TRAVIS_OS_NAME = linux ]; then 6 | target=x86_64-unknown-linux-musl 7 | sort=sort 8 | else 9 | target=x86_64-apple-darwin 10 | sort=gsort # for `sort --sort-version`, from brew's coreutils. 11 | fi 12 | 13 | # Builds for iOS are done on OSX, but require the specific target to be 14 | # installed. 15 | case $TARGET in 16 | aarch64-apple-ios) 17 | rustup target install aarch64-apple-ios 18 | ;; 19 | armv7-apple-ios) 20 | rustup target install armv7-apple-ios 21 | ;; 22 | armv7s-apple-ios) 23 | rustup target install armv7s-apple-ios 24 | ;; 25 | i386-apple-ios) 26 | rustup target install i386-apple-ios 27 | ;; 28 | x86_64-apple-ios) 29 | rustup target install x86_64-apple-ios 30 | ;; 31 | esac 32 | 33 | # This fetches latest stable release 34 | local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ 35 | | cut -d/ -f3 \ 36 | | grep -E '^v[0.1.0-9.]+$' \ 37 | | $sort --version-sort \ 38 | | tail -n1) 39 | curl -LSfs https://japaric.github.io/trust/install.sh | \ 40 | sh -s -- \ 41 | --force \ 42 | --git japaric/cross \ 43 | --tag $tag \ 44 | --target $target 45 | } 46 | 47 | main 48 | -------------------------------------------------------------------------------- /src/cli.yml: -------------------------------------------------------------------------------- 1 | name: lagraph 2 | version: "0.2.1" 3 | about: Display a ping graph in a terminal 4 | args: 5 | - host: 6 | help: The host to ping (required) 7 | index: 1 8 | required: true 9 | 10 | - count: 11 | short: c 12 | long: count 13 | help: Number of pings to perform (default is 0 / unlimited) 14 | takes_value: true 15 | 16 | - no_header: 17 | short: H 18 | long: no-header 19 | help: Don't print the header 20 | 21 | - interval: 22 | short: i 23 | long: interval 24 | help: Interval between pings (in seconds, use . as decimal separator) 25 | takes_value: true 26 | 27 | - max_ping: 28 | short: M 29 | long: max-ping 30 | help: Maximal visible ping value on the graph (in milliseconds) 31 | takes_value: true 32 | 33 | - timestamp: 34 | short: t 35 | long: timestamp 36 | help: Print a timestamp 37 | takes_value: true 38 | possible_values: 39 | - none 40 | - short 41 | - full 42 | 43 | - color: 44 | short: C 45 | long: color 46 | help: Color scheme to use (default is "16color" unless $COLORTERM is "truecolor") 47 | takes_value: true 48 | possible_values: 49 | - none 50 | - 16color 51 | - truecolor 52 | 53 | - saturation: 54 | short: S 55 | long: saturation 56 | help: Saturation of the graph results (0-255, default is 160) 57 | takes_value: true 58 | 59 | - style: 60 | short: s 61 | long: style 62 | help: Bar style to use (default is "bar") 63 | takes_value: true 64 | possible_values: 65 | - bar 66 | - block 67 | - line 68 | - ascii 69 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | environment: 5 | global: 6 | RUST_VERSION: stable 7 | CRATE_NAME: lagraph 8 | 9 | matrix: 10 | # MinGW 11 | - TARGET: i686-pc-windows-gnu 12 | - TARGET: x86_64-pc-windows-gnu 13 | 14 | # MSVC 15 | - TARGET: i686-pc-windows-msvc 16 | - TARGET: x86_64-pc-windows-msvc 17 | 18 | # Testing other channels 19 | - TARGET: x86_64-pc-windows-gnu 20 | RUST_VERSION: nightly 21 | - TARGET: x86_64-pc-windows-msvc 22 | RUST_VERSION: nightly 23 | 24 | install: 25 | - ps: >- 26 | If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { 27 | $Env:PATH += ';C:\msys64\mingw64\bin' 28 | } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { 29 | $Env:PATH += ';C:\msys64\mingw32\bin' 30 | } 31 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 32 | - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% 33 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 34 | - rustc -Vv 35 | - cargo -V 36 | 37 | test_script: 38 | # we don't run the "test phase" when doing deploys 39 | - if [%APPVEYOR_REPO_TAG%]==[false] ( 40 | cargo build --target %TARGET% && 41 | cargo build --target %TARGET% --release && 42 | cargo test --target %TARGET% && 43 | cargo test --target %TARGET% --release 44 | ) 45 | 46 | before_deploy: 47 | - cargo rustc --target %TARGET% --release --bin lagraph -- -C lto 48 | - ps: ci\before_deploy.ps1 49 | 50 | deploy: 51 | artifact: /.*\.zip/ 52 | auth_token: 53 | secure: pQCHVnRYxlJxqk4dem4roOkhemp5J8+tgwhrDgZ8TUSq3M69qGFHr4eT0xTyaD0Y 54 | description: '' 55 | on: 56 | RUST_VERSION: stable 57 | appveyor_repo_tag: true 58 | provider: GitHub 59 | 60 | cache: 61 | - C:\Users\appveyor\.cargo\registry 62 | - target 63 | 64 | branches: 65 | only: 66 | # Release tags 67 | - /^v\d+\.\d+\.\d+.*$/ 68 | - master 69 | 70 | notifications: 71 | - provider: Email 72 | on_build_success: false 73 | 74 | # Building is done in the test phase, so we disable Appveyor's build phase. 75 | build: false 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lagraph 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/lagraph.svg)](https://crates.io/crates/lagraph) 4 | 5 | **lagraph** is a command-line utility that can be used to draw a ping graph over time. 6 | 7 | ## Features 8 | 9 | - Bars drawn using Unicode or ASCII character, supporting "half characters" 10 | for increased precision 11 | - True-color output with configurable saturation 12 | - Setting ping interval and/or count 13 | - Optional short or long timestamp 14 | 15 | ## Use cases 16 | 17 | - Monitoring your connection quality and stability over time. 18 | - This is especially useful when using Wi-Fi or mobile connections such as 4G. 19 | 20 | ## Installation 21 | 22 | ### Using `cargo` 23 | 24 | If you already have [Rust](https://rust-lang.org/) installed, you can use 25 | [Cargo](https://crates.io/) to build and install lagraph: 26 | 27 | ```bash 28 | cargo install lagraph 29 | ``` 30 | 31 | You need rustc 1.30 or later to build lagraph from source. 32 | 33 | ## Usage 34 | 35 | Use `lagraph --help` for a full list of command-line options. 36 | 37 | ### Examples 38 | 39 | Ping an host at the default interval (0.5 seconds): 40 | 41 | ```bash 42 | lagraph 43 | ``` 44 | 45 | Ping an host every 5 seconds, displaying a short timestamp on the left: 46 | 47 | ```bash 48 | lagraph -i 5 -t short 49 | ``` 50 | 51 | Ping an host with a maximum displayable ping value of 100 milliseconds 52 | and remove colors from the output: 53 | 54 | ```bash 55 | lagraph -M 100 -C none 56 | ``` 57 | 58 | ### Setting true-color output by default 59 | 60 | To use true-color output by default, you need to set the environment variable 61 | `COLORTERM` to `truecolor`. You can make this permanent by adding the following 62 | line to your shell startup file (such as `~/.bashrc` or `~/.zshrc`): 63 | 64 | ```bash 65 | export COLORTERM="truecolor" 66 | ``` 67 | 68 | On Windows, this can be done using the following commands in a Command Prompt: 69 | 70 | ```bat 71 | :: Permanently set COLORTERM to "truecolor" for the current user 72 | setx COLORTERM truecolor 73 | :: Sets the variable in the current shell 74 | set COLORTERM=truecolor 75 | ``` 76 | 77 | Note that not all terminals support true-color terminal output; see 78 | [this gist](https://gist.github.com/XVilka/8346728) for more information. 79 | Windows 10 supports true-color terminal output since the Creators Update 80 | (version 1703). 81 | 82 | ## License 83 | 84 | Copyright © 2018-2019 Hugo Locurcio and contributors 85 | 86 | Licensed (at your option) under the [MIT](/LICENSE.MIT.md) 87 | or [Apache 2.0](LICENSE.Apache-2.0.txt) license. 88 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | dist: trusty 5 | language: rust 6 | services: docker 7 | sudo: required 8 | osx_image: xcode10.1 9 | 10 | env: 11 | global: 12 | - CRATE_NAME=lagraph 13 | 14 | matrix: 15 | include: 16 | # Android 17 | # - env: TARGET=aarch64-linux-android DISABLE_TESTS=1 18 | # - env: TARGET=arm-linux-androideabi DISABLE_TESTS=1 19 | # - env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1 20 | # - env: TARGET=i686-linux-android DISABLE_TESTS=1 21 | # - env: TARGET=x86_64-linux-android DISABLE_TESTS=1 22 | 23 | # iOS 24 | # - env: TARGET=aarch64-apple-ios DISABLE_TESTS=1 25 | # os: osx 26 | # - env: TARGET=armv7-apple-ios DISABLE_TESTS=1 27 | # os: osx 28 | # - env: TARGET=armv7s-apple-ios DISABLE_TESTS=1 29 | # os: osx 30 | # - env: TARGET=i386-apple-ios DISABLE_TESTS=1 31 | # os: osx 32 | # - env: TARGET=x86_64-apple-ios DISABLE_TESTS=1 33 | # os: osx 34 | 35 | # Linux 36 | - env: TARGET=aarch64-unknown-linux-gnu 37 | # - env: TARGET=arm-unknown-linux-gnueabi 38 | - env: TARGET=armv7-unknown-linux-gnueabihf 39 | # - env: TARGET=i686-unknown-linux-gnu 40 | - env: TARGET=i686-unknown-linux-musl 41 | # - env: TARGET=mips-unknown-linux-gnu 42 | # - env: TARGET=mips64-unknown-linux-gnuabi64 43 | # - env: TARGET=mips64el-unknown-linux-gnuabi64 44 | # - env: TARGET=mipsel-unknown-linux-gnu 45 | # - env: TARGET=powerpc-unknown-linux-gnu 46 | # - env: TARGET=powerpc64-unknown-linux-gnu 47 | # - env: TARGET=powerpc64le-unknown-linux-gnu 48 | # - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1 49 | # - env: TARGET=x86_64-unknown-linux-gnu 50 | - env: TARGET=x86_64-unknown-linux-musl 51 | 52 | # OSX 53 | # - env: TARGET=i686-apple-darwin 54 | # os: osx 55 | - env: TARGET=x86_64-apple-darwin 56 | os: osx 57 | 58 | # *BSD 59 | # - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1 60 | # - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1 61 | # - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1 62 | 63 | # Windows 64 | - env: TARGET=i686-pc-windows-gnu 65 | - env: TARGET=x86_64-pc-windows-gnu 66 | 67 | # Bare metal 68 | # These targets don't support std and as such are likely not suitable for 69 | # most crates. 70 | # - env: TARGET=thumbv6m-none-eabi 71 | # - env: TARGET=thumbv7em-none-eabi 72 | # - env: TARGET=thumbv7em-none-eabihf 73 | # - env: TARGET=thumbv7m-none-eabi 74 | 75 | # Testing other channels 76 | - env: TARGET=x86_64-unknown-linux-gnu 77 | rust: nightly 78 | - env: TARGET=x86_64-apple-darwin 79 | os: osx 80 | rust: nightly 81 | 82 | before_install: 83 | - set -e 84 | - rustup self update 85 | 86 | install: 87 | - sh ci/install.sh 88 | - source ~/.cargo/env || true 89 | - rustup component add rustfmt 90 | 91 | script: 92 | - cargo fmt --all -- --check --color always 93 | - bash ci/script.sh 94 | 95 | after_script: set +e 96 | 97 | before_deploy: 98 | - sh ci/before_deploy.sh 99 | 100 | deploy: 101 | api_key: 102 | secure: HUOK3q099xcJnws9T/uhHFthgSb3u8kiJ1zinbaXN6wzWy6vZK/ly0ltqA2A5MaHel/SX12IsXU4TsZvnlEo7d/2i236z9Od4TN0SQ/zbsqR0WzBmXJYTN/FeG2wTKx8WAIFUZPE6/FEo2xuKlcxgcXdbB4VaFOC50WgK4BOxTe+tmBSxPpSpCwsRUWaw5Hb6ZZy3AYOfWwScHWuXusrNSkQIQ17ECGFPDMkfKdZQGlawZATf/Yxb4VJxHY3pXN08xmV3dE+3NEhHI1gL1n1jmJBObr474XzeCp2zXfyH1j0p5zV6Vokbo8awmmgAmUo4o0i8rzhNaSjtpYFW14Z2ygADs4LZENsxkPERO1y8187PYap9h355/uBn9ksJBUmgdjDsjfqz+IbS8TPwih5OQ8rpWmfBYRPv4V98qK+xbUnyWZVZScTm/DKiup9yxqr/Q4wFze331edmu1DCLIuP49sHEmWy/+pkNA/7YOt0Vll7ouDzi59LP7L3rJVy4v0DBuPYgigzP44SF8sL2nMJ/1l+v0hEKmtq5pIWArsoVkA5G1hgfAaszj4L8wr2ObEo4+g38dvmNqxSWMzNI2Oa9p9JEE7iNJlr/czqCB4YlI+p/yiDx7c5mMS5PoJ9j6v2XGKnc1MaQelwPFlNdVk7xx1NARHFe9t1mo/SeoXJlU= 103 | file_glob: true 104 | file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.* 105 | on: 106 | condition: $TRAVIS_RUST_VERSION = stable 107 | tags: true 108 | provider: releases 109 | skip_cleanup: true 110 | 111 | cache: cargo 112 | before_cache: 113 | # Travis can't cache files that are not readable by "others" 114 | - chmod -R a+r $HOME/.cargo 115 | 116 | branches: 117 | only: 118 | # release tags 119 | - /^v\d+\.\d+\.\d+.*$/ 120 | - master 121 | 122 | notifications: 123 | email: 124 | on_success: never 125 | -------------------------------------------------------------------------------- /LICENSE.Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // lagraph: Display a ping graph in a terminal 2 | // 3 | // Copyright © 2018-2019 Hugo Locurcio and contributors 4 | // Licensed (at your option) under the MIT or Apache 2 license, 5 | // see `LICENSE.MIT.md` and `LICENSE.Apache-2.0.txt` for details. 6 | 7 | extern crate ansi_term; 8 | extern crate chrono; 9 | extern crate clap; 10 | extern crate terminal_size; 11 | use ansi_term::Colour::{Blue, Green, Red, Yellow, RGB}; 12 | use ansi_term::Style; 13 | use ansi_term::{ANSIString, ANSIStrings}; 14 | use chrono::prelude::*; 15 | use clap::{load_yaml, value_t, value_t_or_exit, App}; 16 | use std::process::Command; 17 | use std::{cmp, env, thread, time}; 18 | use terminal_size::{terminal_size, Width}; 19 | 20 | fn main() { 21 | let yaml = load_yaml!("cli.yml"); 22 | let matches = App::from_yaml(yaml).get_matches(); 23 | 24 | // Initialize settings (with defaults when applicable) 25 | 26 | // The host to ping (required) 27 | let host = value_t_or_exit!(matches, "host", String); 28 | 29 | // Wait time in seconds between each ping 30 | // NOTE: the actual value varies depends on ping and can't be lower than the ping time 31 | // Defaults to 0.5 seconds (2 pings per second) 32 | let wait = (value_t!(matches, "interval", f32).unwrap_or(0.5) * 1000.0) as u64; 33 | 34 | // Maximal ping in the graph (values above will be cut off) 35 | // Defaults to 300 (a sane baseline for most connections) 36 | let max_ping = value_t!(matches, "max_ping", u32).unwrap_or(300); 37 | 38 | // The characters to use for drawing the bars 39 | let bar_character; 40 | let cap_half_character; 41 | // The character that separates the ping value and the bar (can be changed by styles) 42 | let separator; 43 | 44 | // Number of pings to do (0 = no limit, which is the default) 45 | let mut count = value_t!(matches, "count", u32).unwrap_or(0); 46 | 47 | // Default style is "bar" 48 | let style = value_t!(matches, "style", String).unwrap_or_else(|_| String::from("bar")); 49 | 50 | // All available bar styles (not all of them support half-caps) 51 | // If half-caps are not supported, then the half cap is just an empty string 52 | match style.as_ref() { 53 | "bar" => { 54 | bar_character = "▄"; 55 | cap_half_character = "▖"; 56 | separator = "▏"; 57 | } 58 | "block" => { 59 | bar_character = "█"; 60 | cap_half_character = "▌"; 61 | separator = "▏"; 62 | } 63 | "line" => { 64 | bar_character = "▁"; 65 | cap_half_character = ""; 66 | separator = "▏"; 67 | } 68 | _ => { 69 | // Also handles "ascii" case 70 | bar_character = "="; 71 | cap_half_character = "-"; 72 | separator = "|"; 73 | } 74 | } 75 | 76 | // The color scheme to use: 77 | // - `truecolor` does not work on all platforms and terminals, but usually looks best 78 | // and is the most accurate 79 | // - `256color` is more compatible but not as accurate 80 | // - `16color` is the most compatible along with `none` (disabled colors) 81 | // The default value varies depending on the environment variable COLORTERM 82 | let color_default = match env::var("COLORTERM") { 83 | Ok(value) => { 84 | if value == "truecolor" || value == "24bit" { 85 | "truecolor" 86 | } else { 87 | "16color" 88 | } 89 | } 90 | Err(_) => "16color", 91 | }; 92 | 93 | let color = value_t!(matches, "color", String).unwrap_or_else(|_| String::from(color_default)); 94 | 95 | // Whether to print a header or not (default: print header) 96 | let print_header = !matches.is_present("no_header"); 97 | 98 | if print_header { 99 | // If the ping count is 0, display "unlimited" 100 | let count_print = if count == 0 { 101 | String::from("unlimited") 102 | } else { 103 | count.to_string() 104 | }; 105 | 106 | let header: &[ANSIString<'static>] = &[ 107 | Style::new().bold().paint("Ping graph for host "), 108 | Green.bold().underline().paint(host.to_string()), 109 | Style::new().bold().paint(" - updated every "), 110 | Yellow.bold().paint((wait as f32 / 1000.0).to_string()), 111 | Style::new().bold().paint(" seconds - performing "), 112 | Blue.bold().paint(count_print), 113 | Style::new().bold().paint(" pings:"), 114 | ]; 115 | 116 | println!("{}", ANSIStrings(header)); 117 | } 118 | 119 | loop { 120 | // Get the terminal width every iteration so that the ping graph 121 | // adapts to terminal resizes 122 | let size = terminal_size(); 123 | let width = if let Some((Width(w), _)) = size { 124 | // The left column's typical width is substracted to the total width 125 | // FIXME: Take the timestamp into account if present 126 | u32::from(w) - 12 127 | } else { 128 | 80 129 | }; 130 | 131 | // Call the system `ping` command 132 | // Windows uses "-n" to set the ping count, UNIX-like platforms use "-c" 133 | let output = Command::new("ping") 134 | .arg(if cfg!(windows) { "-n" } else { "-c" }) 135 | .arg("1") 136 | .arg(host.to_string()) 137 | .output() 138 | .unwrap(); 139 | 140 | let status = output.status; 141 | // Default to 0 ping in case of errors (for the wait time to make sense) 142 | let mut ping = 0.0; 143 | 144 | if status.success() { 145 | // Ping successful 146 | let output_string = String::from_utf8_lossy(&output.stdout); 147 | 148 | // Trim the output to keep only a string containing the ping value 149 | // The output line is the 2nd one on Linux and macOS and the 3rd one on Windows 150 | // There is a space before "ms" on Linux and macOS but not on Windows 151 | // (in some languages such as English), so it must be trimmed 152 | let ping_string = output_string 153 | .split('\n') 154 | .nth(if cfg!(windows) { 2 } else { 1 }) 155 | .unwrap() 156 | .split('=') 157 | .last() 158 | .unwrap() 159 | .split("ms") 160 | .nth(0) 161 | .unwrap() 162 | .trim(); 163 | 164 | // Convert string to floating-point number 165 | ping = ping_string.parse().unwrap(); 166 | 167 | // Ratio of full screen width 168 | let ratio = ping / max_ping as f32; 169 | 170 | // How many bars to draw 171 | // String.repeat() wants an `usize` 172 | let number_of_bars = (ratio * width as f32) as usize; 173 | 174 | // Ping as displayed as the bars (inaccurate) 175 | let bar_ping = (number_of_bars as f32 / width as f32 / ratio * ping).round(); 176 | // Ping as displayed by the bars + 1 (also inaccurate) 177 | let bar_ping_next = ((number_of_bars + 1) as f32 / width as f32 / ratio * ping).round(); 178 | // Average of bar_ping and bar_ping_next (to check if a cap should be added for precision) 179 | let bar_ping_half = (bar_ping + bar_ping_next) / 2.0; 180 | 181 | // Don't draw caps if user has turned them off or there is no need 182 | // (in case there is sub-millisecond precision thanks to large terminal width) 183 | // (or if the bar has overflowed) 184 | let draw_cap = !(max_ping <= width || number_of_bars >= (width) as usize); 185 | 186 | // Draw a cap for sub-character precision 187 | let cap = if draw_cap && ping >= bar_ping_half && ping < bar_ping_next { 188 | // There should be a cap 189 | cap_half_character 190 | } else { 191 | // There shouldn't be a cap ("empty" cap) 192 | "" 193 | }; 194 | 195 | // Ping bar/number color 196 | let ping_color; 197 | 198 | match color.as_ref() { 199 | "truecolor" => { 200 | // The higher this value, the less colored the bars are 201 | let desaturation = 255 - value_t!(matches, "saturation", u8).unwrap_or(160); 202 | 203 | // No red at 0% bar width, fully red at 100% bar width 204 | let red = cmp::min( 205 | (255.0 + (512.0 - 2.0 * f32::from(desaturation)) * (ratio - 0.5)) as i16, 206 | 255 as i16, 207 | ) as u8; 208 | 209 | // Fully green from 0% to 50% bar width, no green at 100% bar width 210 | let green = cmp::min( 211 | 255, 212 | cmp::max( 213 | (255.0 - (512.0 - f32::from(desaturation) * 2.0) * (ratio - 0.5)) 214 | as i16, 215 | i16::from(desaturation), 216 | ), 217 | ) as u8; 218 | 219 | // Constant value 220 | let blue = desaturation; 221 | 222 | ping_color = RGB(red, green, blue); 223 | } 224 | _ => { 225 | if ratio >= 0.0 && ratio <= 0.33 { 226 | ping_color = Green; 227 | } else if ratio > 0.33 && ratio <= 0.67 { 228 | ping_color = Yellow; 229 | } else { 230 | ping_color = Red; 231 | } 232 | } 233 | } 234 | 235 | // String containing the whole bar (including the cap) 236 | let bar_string = [ 237 | bar_character.repeat(cmp::min(number_of_bars, width as usize)), 238 | cap.to_string(), 239 | ] 240 | .join(""); 241 | 242 | // Timestamp 243 | 244 | let now = Local::now(); 245 | let timestamp_setting = 246 | value_t!(matches, "timestamp", String).unwrap_or_else(|_| String::from("none")); 247 | let timestamp = match timestamp_setting.as_ref() { 248 | "short" => { 249 | // Only hours, minutes and seconds 250 | now.format("%H:%M:%S").to_string() 251 | } 252 | "full" => { 253 | // Full date in a SQL-like format 254 | now.format("%Y-%m-%d %H:%M:%S").to_string() 255 | } 256 | _ => { 257 | // This also matches the default "none" setting 258 | // No timestamp 259 | String::from("") 260 | } 261 | }; 262 | 263 | // Print the ping graph (and cap if needed to avoid line breaks) 264 | println!( 265 | "{} {} {} {}", 266 | // The optional timestamp 267 | timestamp, 268 | // The ping value with a " ms" suffix (right-aligned) 269 | ping_color.paint(format!( 270 | "{:>7}", 271 | [(ping as u32).to_string(), "ms".to_string()].join(" ") 272 | )), 273 | // The separator character (depends on style) 274 | separator, 275 | // The bar 276 | ping_color.paint(bar_string) 277 | ); 278 | } else { 279 | // Ping failed 280 | let err = output.stderr; 281 | println!("{}", Red.bold().paint(String::from_utf8_lossy(&err))); 282 | } 283 | 284 | if count != 0 { 285 | count -= 1; 286 | 287 | // Exit if the limit of pings has been reached 288 | if count == 0 { 289 | break; 290 | } 291 | } 292 | 293 | // Sleep after receiving the ping result or an error 294 | // Try to sleep around the "wait" time in milliseconds 295 | // by compensating the value based on the ping time 296 | let sleep = time::Duration::from_millis(wait - cmp::min(ping as u64, wait as u64)); 297 | thread::sleep(sleep); 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "android_system_properties" 7 | version = "0.1.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" 10 | dependencies = [ 11 | "libc", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.12.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 19 | dependencies = [ 20 | "winapi", 21 | ] 22 | 23 | [[package]] 24 | name = "atty" 25 | version = "0.2.11" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 28 | dependencies = [ 29 | "libc", 30 | "termion", 31 | "winapi", 32 | ] 33 | 34 | [[package]] 35 | name = "autocfg" 36 | version = "1.0.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 39 | 40 | [[package]] 41 | name = "bitflags" 42 | version = "1.3.2" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 45 | 46 | [[package]] 47 | name = "bumpalo" 48 | version = "3.10.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" 51 | 52 | [[package]] 53 | name = "cc" 54 | version = "1.0.73" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 57 | 58 | [[package]] 59 | name = "cfg-if" 60 | version = "1.0.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 63 | 64 | [[package]] 65 | name = "chrono" 66 | version = "0.4.23" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" 69 | dependencies = [ 70 | "iana-time-zone", 71 | "js-sys", 72 | "num-integer", 73 | "num-traits", 74 | "time", 75 | "wasm-bindgen", 76 | "winapi", 77 | ] 78 | 79 | [[package]] 80 | name = "clap" 81 | version = "3.2.23" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" 84 | dependencies = [ 85 | "atty", 86 | "bitflags", 87 | "clap_lex", 88 | "indexmap", 89 | "strsim", 90 | "termcolor", 91 | "textwrap", 92 | "yaml-rust", 93 | ] 94 | 95 | [[package]] 96 | name = "clap_lex" 97 | version = "0.2.2" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613" 100 | dependencies = [ 101 | "os_str_bytes", 102 | ] 103 | 104 | [[package]] 105 | name = "core-foundation-sys" 106 | version = "0.8.3" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 109 | 110 | [[package]] 111 | name = "errno" 112 | version = "0.2.8" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 115 | dependencies = [ 116 | "errno-dragonfly", 117 | "libc", 118 | "winapi", 119 | ] 120 | 121 | [[package]] 122 | name = "errno-dragonfly" 123 | version = "0.1.2" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 126 | dependencies = [ 127 | "cc", 128 | "libc", 129 | ] 130 | 131 | [[package]] 132 | name = "hashbrown" 133 | version = "0.11.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 136 | 137 | [[package]] 138 | name = "iana-time-zone" 139 | version = "0.1.44" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "808cf7d67cf4a22adc5be66e75ebdf769b3f2ea032041437a7061f97a63dad4b" 142 | dependencies = [ 143 | "android_system_properties", 144 | "core-foundation-sys", 145 | "js-sys", 146 | "wasm-bindgen", 147 | "winapi", 148 | ] 149 | 150 | [[package]] 151 | name = "indexmap" 152 | version = "1.7.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 155 | dependencies = [ 156 | "autocfg", 157 | "hashbrown", 158 | ] 159 | 160 | [[package]] 161 | name = "io-lifetimes" 162 | version = "1.0.3" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" 165 | dependencies = [ 166 | "libc", 167 | "windows-sys 0.42.0", 168 | ] 169 | 170 | [[package]] 171 | name = "js-sys" 172 | version = "0.3.59" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 175 | dependencies = [ 176 | "wasm-bindgen", 177 | ] 178 | 179 | [[package]] 180 | name = "lagraph" 181 | version = "0.2.1" 182 | dependencies = [ 183 | "ansi_term", 184 | "chrono", 185 | "clap", 186 | "terminal_size", 187 | ] 188 | 189 | [[package]] 190 | name = "libc" 191 | version = "0.2.137" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 194 | 195 | [[package]] 196 | name = "linked-hash-map" 197 | version = "0.5.4" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 200 | 201 | [[package]] 202 | name = "linux-raw-sys" 203 | version = "0.1.3" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" 206 | 207 | [[package]] 208 | name = "log" 209 | version = "0.4.17" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 212 | dependencies = [ 213 | "cfg-if", 214 | ] 215 | 216 | [[package]] 217 | name = "num-integer" 218 | version = "0.1.39" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 221 | dependencies = [ 222 | "num-traits", 223 | ] 224 | 225 | [[package]] 226 | name = "num-traits" 227 | version = "0.2.6" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 230 | 231 | [[package]] 232 | name = "once_cell" 233 | version = "1.13.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 236 | 237 | [[package]] 238 | name = "os_str_bytes" 239 | version = "6.0.0" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" 242 | 243 | [[package]] 244 | name = "proc-macro2" 245 | version = "1.0.43" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" 248 | dependencies = [ 249 | "unicode-ident", 250 | ] 251 | 252 | [[package]] 253 | name = "quote" 254 | version = "1.0.21" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 257 | dependencies = [ 258 | "proc-macro2", 259 | ] 260 | 261 | [[package]] 262 | name = "redox_syscall" 263 | version = "0.1.51" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" 266 | 267 | [[package]] 268 | name = "redox_termios" 269 | version = "0.1.1" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 272 | dependencies = [ 273 | "redox_syscall", 274 | ] 275 | 276 | [[package]] 277 | name = "rustix" 278 | version = "0.36.4" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" 281 | dependencies = [ 282 | "bitflags", 283 | "errno", 284 | "io-lifetimes", 285 | "libc", 286 | "linux-raw-sys", 287 | "windows-sys 0.42.0", 288 | ] 289 | 290 | [[package]] 291 | name = "strsim" 292 | version = "0.10.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 295 | 296 | [[package]] 297 | name = "syn" 298 | version = "1.0.99" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 301 | dependencies = [ 302 | "proc-macro2", 303 | "quote", 304 | "unicode-ident", 305 | ] 306 | 307 | [[package]] 308 | name = "termcolor" 309 | version = "1.1.2" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 312 | dependencies = [ 313 | "winapi-util", 314 | ] 315 | 316 | [[package]] 317 | name = "terminal_size" 318 | version = "0.2.5" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" 321 | dependencies = [ 322 | "rustix", 323 | "windows-sys 0.45.0", 324 | ] 325 | 326 | [[package]] 327 | name = "termion" 328 | version = "1.5.1" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 331 | dependencies = [ 332 | "libc", 333 | "redox_syscall", 334 | "redox_termios", 335 | ] 336 | 337 | [[package]] 338 | name = "textwrap" 339 | version = "0.16.0" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" 342 | 343 | [[package]] 344 | name = "time" 345 | version = "0.1.43" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 348 | dependencies = [ 349 | "libc", 350 | "winapi", 351 | ] 352 | 353 | [[package]] 354 | name = "unicode-ident" 355 | version = "1.0.3" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 358 | 359 | [[package]] 360 | name = "wasm-bindgen" 361 | version = "0.2.82" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" 364 | dependencies = [ 365 | "cfg-if", 366 | "wasm-bindgen-macro", 367 | ] 368 | 369 | [[package]] 370 | name = "wasm-bindgen-backend" 371 | version = "0.2.82" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" 374 | dependencies = [ 375 | "bumpalo", 376 | "log", 377 | "once_cell", 378 | "proc-macro2", 379 | "quote", 380 | "syn", 381 | "wasm-bindgen-shared", 382 | ] 383 | 384 | [[package]] 385 | name = "wasm-bindgen-macro" 386 | version = "0.2.82" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" 389 | dependencies = [ 390 | "quote", 391 | "wasm-bindgen-macro-support", 392 | ] 393 | 394 | [[package]] 395 | name = "wasm-bindgen-macro-support" 396 | version = "0.2.82" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" 399 | dependencies = [ 400 | "proc-macro2", 401 | "quote", 402 | "syn", 403 | "wasm-bindgen-backend", 404 | "wasm-bindgen-shared", 405 | ] 406 | 407 | [[package]] 408 | name = "wasm-bindgen-shared" 409 | version = "0.2.82" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" 412 | 413 | [[package]] 414 | name = "winapi" 415 | version = "0.3.9" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 418 | dependencies = [ 419 | "winapi-i686-pc-windows-gnu", 420 | "winapi-x86_64-pc-windows-gnu", 421 | ] 422 | 423 | [[package]] 424 | name = "winapi-i686-pc-windows-gnu" 425 | version = "0.4.0" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 428 | 429 | [[package]] 430 | name = "winapi-util" 431 | version = "0.1.5" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 434 | dependencies = [ 435 | "winapi", 436 | ] 437 | 438 | [[package]] 439 | name = "winapi-x86_64-pc-windows-gnu" 440 | version = "0.4.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 443 | 444 | [[package]] 445 | name = "windows-sys" 446 | version = "0.42.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 449 | dependencies = [ 450 | "windows_aarch64_gnullvm", 451 | "windows_aarch64_msvc", 452 | "windows_i686_gnu", 453 | "windows_i686_msvc", 454 | "windows_x86_64_gnu", 455 | "windows_x86_64_gnullvm", 456 | "windows_x86_64_msvc", 457 | ] 458 | 459 | [[package]] 460 | name = "windows-sys" 461 | version = "0.45.0" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 464 | dependencies = [ 465 | "windows-targets", 466 | ] 467 | 468 | [[package]] 469 | name = "windows-targets" 470 | version = "0.42.1" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" 473 | dependencies = [ 474 | "windows_aarch64_gnullvm", 475 | "windows_aarch64_msvc", 476 | "windows_i686_gnu", 477 | "windows_i686_msvc", 478 | "windows_x86_64_gnu", 479 | "windows_x86_64_gnullvm", 480 | "windows_x86_64_msvc", 481 | ] 482 | 483 | [[package]] 484 | name = "windows_aarch64_gnullvm" 485 | version = "0.42.1" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" 488 | 489 | [[package]] 490 | name = "windows_aarch64_msvc" 491 | version = "0.42.1" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" 494 | 495 | [[package]] 496 | name = "windows_i686_gnu" 497 | version = "0.42.1" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" 500 | 501 | [[package]] 502 | name = "windows_i686_msvc" 503 | version = "0.42.1" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" 506 | 507 | [[package]] 508 | name = "windows_x86_64_gnu" 509 | version = "0.42.1" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" 512 | 513 | [[package]] 514 | name = "windows_x86_64_gnullvm" 515 | version = "0.42.1" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" 518 | 519 | [[package]] 520 | name = "windows_x86_64_msvc" 521 | version = "0.42.1" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" 524 | 525 | [[package]] 526 | name = "yaml-rust" 527 | version = "0.4.5" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 530 | dependencies = [ 531 | "linked-hash-map", 532 | ] 533 | --------------------------------------------------------------------------------