Merge branch 'main' into dependabot/github_actions/docker/setup-buildx-action-2

This commit is contained in:
Orhun Parmaksız 2022-09-06 22:22:42 +02:00
commit 0e8a645e6c
No known key found for this signature in database
GPG Key ID: F83424824B3E4B90
36 changed files with 872 additions and 380 deletions

View File

@ -1 +0,0 @@
msrv = "1.56.1"

View File

@ -4,6 +4,7 @@
/target/
/.cargo/
/assets/
/config/
# Files
.editorconfig

1
.github/FUNDING.yml vendored
View File

@ -1 +1,2 @@
github: orhun
patreon: orhunp

View File

@ -43,15 +43,7 @@ jobs:
override: true
- name: Cache Cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
uses: Swatinem/rust-cache@v1
- name: Build
uses: actions-rs/cargo@v1
@ -86,15 +78,7 @@ jobs:
override: true
- name: Cache Cargo dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
uses: Swatinem/rust-cache@v1
- name: Setup cargo-tarpaulin
shell: bash
@ -165,7 +149,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings
args: --tests -- -D warnings
- name: Run cargo-deny
uses: EmbarkStudios/cargo-deny-action@v1

View File

@ -22,7 +22,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v4
with:
images: |
orhunp/systeroid

View File

@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.1] - 2022-08-30
### Updated
- Update the allowed licenses for cargo-deny
- Add metadata for cargo-binstall
- Remove unnecessary dirs dependency
- Bump dependencies
## [0.2.0] - 2022-08-11
### Features
- Add a configuration file ([#12](https://github.com/orhun/git-cliff/issues/12))
- See [configuration](https://github.com/orhun/systeroid#configuration) and [`systeroid.conf`](https://github.com/orhun/systeroid/blob/main/config/systeroid.conf)
- (tui) Show deprecated values optionally via `--deprecated` flag
### Documentation
- Update broken links
### Miscellaneous Tasks
- Update MSRV to 1.57.0
- Switch to Rust stable builds
- Bump dependencies
- Enable [GitHub Sponsors](https://github.com/sponsors/orhun) for funding
- Consider supporting my open source work 💖
## [0.1.1] - 2022-04-19
### Added
- (cli) Support explaining multiple parameters

296
Cargo.lock generated
View File

@ -8,6 +8,17 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -67,12 +78,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -102,15 +107,15 @@ dependencies = [
[[package]]
name = "colorsys"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dfdf9179d546b55ff3f88c9d93ecfaa3e9760163da5a1080af5243230dbbb70"
checksum = "52c2ad453c82bd637e3969dc52f06676610db0b20c607bf0634c7e9d840789e8"
[[package]]
name = "copypasta"
version = "0.7.1"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b"
checksum = "d7216b5c1e9ad3867252505995b02d01c6fa7e6db0d8abd42634352ef377777e"
dependencies = [
"clipboard-win",
"objc",
@ -122,9 +127,9 @@ dependencies = [
[[package]]
name = "copypasta-ext"
version = "0.3.7"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2f548212db51db2dba038e6e86c98a5d4a8ab0767ab230673a28be89a45b87"
checksum = "af4c1c3f959cd8047b935d503c30e8bdfc9f7539493962ec3e45b9f0d305cbcc"
dependencies = [
"copypasta",
"libc",
@ -143,9 +148,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.2"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -153,9 +158,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@ -164,25 +169,26 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.7"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.7"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
dependencies = [
"cfg-if",
"lazy_static",
"once_cell",
]
[[package]]
@ -215,6 +221,12 @@ dependencies = [
"libloading",
]
[[package]]
name = "dlv-list"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
[[package]]
name = "downcast-rs"
version = "1.2.0"
@ -223,19 +235,17 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "either"
version = "1.6.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "flate2"
version = "1.0.22"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
]
@ -256,9 +266,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.5"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
@ -267,9 +277,9 @@ dependencies = [
[[package]]
name = "globset"
version = "0.4.8"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
dependencies = [
"aho-corasick",
"bstr",
@ -289,6 +299,15 @@ dependencies = [
"walkdir",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -318,9 +337,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.1"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]]
name = "lazy-bytes-cast"
@ -336,9 +355,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.119"
version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]]
name = "libloading"
@ -352,9 +371,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
@ -370,15 +389,15 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.3.1"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357"
checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
dependencies = [
"libc",
]
@ -400,22 +419,20 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "nix"
version = "0.22.3"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
@ -423,13 +440,12 @@ dependencies = [
[[package]]
name = "nom"
version = "7.1.0"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
"version_check",
]
[[package]]
@ -479,15 +495,25 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.10.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]]
name = "ordered-multimap"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
dependencies = [
"dlv-list",
"hashbrown",
]
[[package]]
name = "parseit"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b1326519874d2c452c203ca512d83be71b4703e8d848a9903f18771660f613"
checksum = "efbe4a78e155d43f845fb833df08c11fa29701493a9d735d5119462313e6a97c"
dependencies = [
"flate2",
"globwalk",
@ -497,17 +523,17 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "proc-macro2"
version = "1.0.36"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
@ -521,18 +547,18 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.15"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.5.2"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque",
@ -542,9 +568,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.9.2"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@ -554,9 +580,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.11"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
@ -572,19 +598,20 @@ dependencies = [
[[package]]
name = "redox_users"
version = "0.4.0"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom",
"redox_syscall",
"thiserror",
]
[[package]]
name = "regex"
version = "1.5.5"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
"aho-corasick",
"memchr",
@ -593,15 +620,25 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "rust-ini"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "ryu"
version = "1.0.9"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "same-file"
@ -626,18 +663,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.136"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [
"proc-macro2",
"quote",
@ -646,9 +683,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.79"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
dependencies = [
"itoa",
"ryu",
@ -657,15 +694,15 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "smithay-client-toolkit"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a"
checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
dependencies = [
"bitflags",
"dlib",
@ -681,9 +718,9 @@ dependencies = [
[[package]]
name = "smithay-clipboard"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55"
checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8"
dependencies = [
"smithay-client-toolkit",
"wayland-client",
@ -691,20 +728,20 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.86"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "sysctl"
version = "0.4.4"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1123645dfaf2b5eac6b6c88addafc359c789b8ef2a770ecaef758c1ddf363ea4"
checksum = "f99d037b2bef227ab8963f4b0acc33ecbb1f9a2e7365add7789372b387ec19e1"
dependencies = [
"bitflags",
"byteorder",
@ -715,7 +752,7 @@ dependencies = [
[[package]]
name = "systeroid"
version = "0.1.1"
version = "0.2.1"
dependencies = [
"getopts",
"systeroid-core",
@ -723,13 +760,14 @@ dependencies = [
[[package]]
name = "systeroid-core"
version = "0.1.1"
version = "0.2.1"
dependencies = [
"colored",
"dirs-next",
"lazy_static",
"parseit",
"rayon",
"rust-ini",
"serde",
"serde_json",
"sysctl",
@ -738,7 +776,7 @@ dependencies = [
[[package]]
name = "systeroid-tui"
version = "0.1.1"
version = "0.2.1"
dependencies = [
"colorsys",
"copypasta-ext",
@ -764,18 +802,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.30"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487"
dependencies = [
"proc-macro2",
"quote",
@ -793,9 +831,9 @@ dependencies = [
[[package]]
name = "tui"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96fe69244ec2af261bced1d9046a6fee6c8c2a6b0228e59e5ba39bc8ba4ed729"
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
dependencies = [
"bitflags",
"cassowary",
@ -804,6 +842,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-ident"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
@ -816,12 +860,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
@ -841,15 +879,15 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wayland-client"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f"
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
dependencies = [
"bitflags",
"downcast-rs",
@ -863,9 +901,9 @@ dependencies = [
[[package]]
name = "wayland-commons"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e"
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
dependencies = [
"nix",
"once_cell",
@ -875,9 +913,9 @@ dependencies = [
[[package]]
name = "wayland-cursor"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd"
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
dependencies = [
"nix",
"wayland-client",
@ -886,9 +924,9 @@ dependencies = [
[[package]]
name = "wayland-protocols"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
dependencies = [
"bitflags",
"wayland-client",
@ -898,9 +936,9 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0"
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
dependencies = [
"proc-macro2",
"quote",
@ -909,9 +947,9 @@ dependencies = [
[[package]]
name = "wayland-sys"
version = "0.29.4"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4"
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
dependencies = [
"dlib",
"lazy_static",
@ -920,9 +958,9 @@ dependencies = [
[[package]]
name = "which"
version = "4.2.4"
version = "4.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2"
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
dependencies = [
"either",
"lazy_static",
@ -962,21 +1000,21 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "x11-clipboard"
version = "0.5.3"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c"
checksum = "6a7468a5768fea473e6c8c0d4b60d6d7001a64acceaac267207ca0281e1337e8"
dependencies = [
"xcb",
]
[[package]]
name = "xcb"
version = "0.10.1"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c"
checksum = "b127bf5bfe9dbb39118d6567e3773d4bbc795411a8e1ef7b7e056bccac0011a9"
dependencies = [
"bitflags",
"libc",
"log",
"quick-xml",
]

View File

@ -93,6 +93,7 @@ Although **systeroid** does not need the parameter section to be specified expli
- [Changing the colors](#changing-the-colors)
- [Viewing the parameter documentation](#viewing-the-parameter-documentation)
- [Setting the refresh rate](#setting-the-refresh-rate)
- [Configuration](#configuration)
- [Resources](#resources)
- [References](#references)
- [Logo](#logo)
@ -215,6 +216,7 @@ systeroid [options] [variable[=value] ...] --load[=<file>]
-P, --no-pager do not pipe output into a pager
-v, --verbose enable verbose logging
--tui show terminal user interface
-c, --config <path> set the path of the configuration file
-h, --help display this help and exit (-d)
-V, --version output version information and exit
```
@ -415,6 +417,8 @@ systeroid-tui [options]
--fg-color <color>
set the foreground color [default: white]
-n, --no-docs do not show the kernel documentation
--deprecated include deprecated variables while listing
-c, --config <path> set the path of the configuration file
-h, --help display this help and exit
-V, --version output version information and exit
```
@ -547,6 +551,28 @@ It is possible to specify a value in milliseconds via `--tick-rate` argument for
systeroid-tui --tick-rate 500
```
## Configuration
**systeroid** can be configured with a configuration file that uses the [INI format](https://en.wikipedia.org/wiki/INI_file). It can be specified via `--config` or `SYSTEROID_CONFIG` environment variable. It can also be placed in one of the following global locations:
- `$HOME/.config/systeroid/systeroid.conf`
- `$HOME/.systeroid/systeroid.conf`
```sh
# set the config path via argument
systeroid --config config/systeroid.conf
# set the config path via env
SYSTEROID_CONFIG=config/systeroid.conf systeroid
# use a global path
mkdir -p "$HOME/.config/systeroid"
cp config/systeroid.conf "$HOME/.config/systeroid"
systeroid
```
See the example [systeroid.conf](./config/systeroid.conf) for the configuration options.
## Resources
### References
@ -557,9 +583,7 @@ systeroid-tui --tick-rate 500
### Logo
**systeroid** logo was originally painted by [Ryan Tippery](https://www.ryantippery.com/about) as a part of the [Compositions](https://www.ryantippery.com/compositions/) art collection and it is put together by me using the [Filled Spots](https://www.fontspace.com/filled-spots-font-f30755) font. Shout out to Ryan for letting me use his painting for the logo! **<3**
Check out his [store](https://www.ryantippery.com/store) for a fine piece of similar art. Kudos!
**systeroid** logo was originally painted by [Ryan Tippery](https://ryantippery.com) as a part of the [Compositions](https://ryantippery.com/art/compositions) art collection and it is put together by me using the [Filled Spots](https://www.fontspace.com/filled-spots-font-f30755) font. Shout out to Ryan for letting me use his painting for the logo! **<3** Kudos!
### Social Links
@ -570,7 +594,7 @@ Check out his [store](https://www.ryantippery.com/store) for a fine piece of sim
### Funding
If you find **systeroid** and/or other projects on my [GitHub profile](https://github.com/orhun/) useful, consider [becoming a patron](https://www.patreon.com/join/orhunp)!
If you find **systeroid** and/or other projects on my [GitHub profile](https://github.com/orhun/) useful, consider supporting me on [GitHub Sponsors](https://github.com/sponsors/orhun) or [becoming a patron](https://www.patreon.com/join/orhunp)!
[![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dorhunp%26type%3Dpatrons&style=flat&logo=Patreon&labelColor=000000&color=CECDCB&logoColor=CECDCB)](https://patreon.com/join/orhunp)
[![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dorhunp%26type%3Dpledges&style=flat&logo=Patreon&labelColor=000000&color=CECDCB&logoColor=CECDCB&label=)](https://patreon.com/join/orhunp)

View File

@ -18,6 +18,6 @@ up_to_date_approvals = true
delete_merged_branches = true
update_base_for_deletes = true
use_codeowners = true
use_squash_merge = true
commit_title = "Merge ${PR_REFS}"
timeout_sec = 36000
cut_body_after = "<details>"

66
config/systeroid.conf Normal file
View File

@ -0,0 +1,66 @@
; systeroid ~ configuration file
; https://github.com/orhun/systeroid
;
; Each line either contains a comment or a command line argument grouped under a section.
; Run "systeroid --help" or "systeroid-tui --help" to get a list of all possible configuration options.
[general]
; display the deprecated parameters such as base_reachable_time and retrans_time while listing
; See https://bugzilla.redhat.com/show_bug.cgi?id=152435
display_deprecated = false
; path of the Linux kernel documentation
; this is distro dependent, systeroid checks the following locations as default:
; - /usr/share/doc/linux/
; - /usr/share/doc/linux-doc/
; - /usr/share/doc/linux-docs/
; - /usr/share/doc/kernel-doc-*/Documentation/
kernel_docs = "/usr/share/doc/linux"
[cli]
; enable verbose logging
verbose = false
; ignore unknown variable errors
ignore_errors = true
; do not print variable after the value is set
quiet = false
; do not pipe output into a pager
; note that the default pager is less(1) and you can change it by using `PAGER` environment variable
no_pager = false
; display type for the parameter, available options are:
; - default: print the parameter name along with its value
; - name: print only the name of the parameter
; - value: print only the value of the parameter
; - binary: print only the value of the parameter without new line
display_type = "default"
; output type for the list, available options are:
; - default: print the output as is
; - tree: print the output in a tree-like format
; - json: print the output in JSON format
output_type = "default"
[cli.colors]
; available colors are defined in https://docs.rs/colored/latest/colored/enum.Color.html
; default color for the symbols
default_color = "bright black"
; section colors
section_abi = "red"
section_fs = "green"
section_kernel = "magenta"
section_net = "blue"
section_sunrpc = "yellow"
section_user = "cyan"
section_vm = "bright red"
section_unknown = "white"
[tui]
; tick rate of the terminal
tick_rate = 250
; disable showing the parameter documentation
no_docs = true
[tui.colors]
; available colors are defined in https://docs.rs/tui/latest/tui/style/enum.Color.html
; terminal foreground color
fg_color = "white"
; terminal background color
bg_color = "black"

View File

@ -8,7 +8,8 @@ allow = [
"Apache-2.0",
"BSL-1.0",
"MPL-2.0",
"ISC"
"ISC",
"Unicode-DFS-2016"
]
[sources]

View File

@ -1,6 +1,6 @@
.\" Manpage for systeroid-tui
.TH SYSTEROID-TUI "8" "2022-04-19" "systeroid-tui" "System Administration"
.TH SYSTEROID-TUI "8" "2022-08-30" "systeroid-tui" "System Administration"
.SH NAME
systeroid-tui \- manage kernel parameters with a terminal user interface
@ -34,6 +34,9 @@ Use this option to set the foreground color. [default: white]
\fB\-n\fR, \fB\-\-no\-docs\fR
Do not show the kernel documentation.
.TP
\fB\-\-deprecated\fR
Include deprecated variables while listing.
.TP
\fB\-h\fR, \fB\-\-help\fR
Display help text and exit.
.TP

View File

@ -1,6 +1,6 @@
.\" Manpage for systeroid
.TH SYSTEROID "8" "2022-04-19" "systeroid" "System Administration"
.TH SYSTEROID "8" "2022-08-30" "systeroid" "System Administration"
.SH NAME
systeroid \- configure kernel parameters at runtime

View File

@ -1,6 +1,6 @@
[package]
name = "systeroid-core"
version = "0.1.1" # managed by release.sh
version = "0.2.1" # managed by release.sh
description = "Core library of systeroid"
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
license = "MIT OR Apache-2.0"
@ -12,12 +12,13 @@ edition = "2021"
rust-version = "1.56.1"
[dependencies]
sysctl = "0.4.4"
thiserror = "1.0.29"
sysctl = "0.5.2"
thiserror = "1.0.34"
lazy_static = "1.4.0"
rayon = "1.5.2"
rayon = "1.5.3"
colored = "2.0.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
serde = { version = "1.0.144", features = ["derive"] }
serde_json = "1.0.85"
dirs-next = "2.0.0"
parseit = { version = "0.1.0", features = ["gzip"] }
parseit = { version = "0.1.1", features = ["gzip"] }
rust-ini = "0.18.0"

View File

@ -1,9 +1,26 @@
use crate::sysctl::display::DisplayType;
use crate::error::Result;
use crate::sysctl::r#type::{DisplayType, OutputType};
use crate::sysctl::section::Section;
use colored::Color;
use ini::Ini;
use std::collections::HashMap;
use std::path::PathBuf;
/* Macro for the concise initialization of HashMap */
/// Default configuration file.
pub const DEFAULT_CONFIG: &str = "systeroid.conf";
/// Environment variable for setting the path of the configuration file.
pub const CONFIG_ENV: &str = "SYSTEROID_CONFIG";
lazy_static! {
/// Default locations for the configuration file.
pub static ref DEFAULT_CONFIG_PATHS: Vec<Option<PathBuf>> = vec![
dirs_next::config_dir().map(|p| p.join("systeroid").join(DEFAULT_CONFIG)),
dirs_next::home_dir().map(|p| p.join(".systeroid").join(DEFAULT_CONFIG)),
];
}
/// Macro for the concise initialization of HashMap
macro_rules! map {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
@ -12,9 +29,31 @@ macro_rules! map {
}}
}
/// Macro for parsing a boolean value from INI format
macro_rules! parse_ini_flag {
($self: ident, $config: ident, $section: ident, $name: ident) => {
if let Some($name) = $section.get(stringify!($name)) {
$self.$config.$name = $name == "true";
}
};
}
/// Configuration.
#[derive(Clone, Debug)]
pub struct Config {
/// Whether if the deprecated variables should be included while listing.
pub display_deprecated: bool,
/// Path of the Linux kernel documentation.
pub kernel_docs: Option<PathBuf>,
/// CLI configuration.
pub cli: CliConfig,
/// TUI configuration.
pub tui: TuiConfig,
}
/// CLI configuration.
#[derive(Clone, Debug)]
pub struct CliConfig {
/// Whether if the verbose logging is enabled.
pub verbose: bool,
/// Whether if the errors should be ignored.
@ -23,33 +62,196 @@ pub struct Config {
pub quiet: bool,
/// Whether if the pager is disabled.
pub no_pager: bool,
/// Sections and the corresponding colors.
pub section_colors: HashMap<Section, Color>,
/// Default color for the output
pub default_color: Color,
/// Display type of the kernel parameters.
pub display_type: DisplayType,
/// Output type of the application.
pub output_type: OutputType,
/// Color configuration.
pub color: CliColorConfig,
}
/// CLI color configuration.
#[derive(Clone, Debug)]
pub struct CliColorConfig {
/// Default color for the output
pub default_color: Color,
/// Sections and the corresponding colors.
pub section_colors: HashMap<Section, Color>,
}
/// TUI configuration.
#[derive(Clone, Debug)]
pub struct TuiConfig {
/// Refresh rate of the terminal.
pub tick_rate: u64,
/// Do not parse/show Linux kernel documentation.
pub no_docs: bool,
/// Color configuration.
pub color: TuiColorConfig,
}
/// TUI color configuration.
#[derive(Clone, Debug)]
pub struct TuiColorConfig {
/// Foreground color.
pub fg_color: String,
/// Background color.
pub bg_color: String,
}
impl Config {
/// Parses the configuration file and overrides values.
pub fn parse(&mut self, path: Option<PathBuf>) -> Result<()> {
let mut config_paths = DEFAULT_CONFIG_PATHS.clone();
if path.is_some() {
config_paths.insert(0, path);
}
let mut config_path = None;
for path in config_paths.into_iter().flatten() {
if path.exists() {
config_path = Some(path);
break;
}
}
if let Some(path) = config_path {
let ini = Ini::load_from_file(path)?;
if let Some(general_section) = ini.section(Some("general")) {
if let Some(display_deprecated) = general_section.get("display_deprecated") {
self.display_deprecated = display_deprecated == "true";
}
if let Some(kernel_docs) = general_section.get("kernel_docs") {
self.kernel_docs = Some(PathBuf::from(kernel_docs));
}
}
if let Some(section) = ini.section(Some("cli")) {
parse_ini_flag!(self, cli, section, verbose);
parse_ini_flag!(self, cli, section, ignore_errors);
parse_ini_flag!(self, cli, section, quiet);
parse_ini_flag!(self, cli, section, no_pager);
if let Some(display_type) = section.get("display_type").map(DisplayType::from) {
self.cli.display_type = display_type;
}
if let Some(output_type) = section.get("output_type").map(OutputType::from) {
self.cli.output_type = output_type;
}
}
if let Some(section) = ini.section(Some("cli.colors")) {
if let Some(default_color) = section
.get("default_color")
.and_then(|v| Color::try_from(v).ok())
{
self.cli.color.default_color = default_color;
}
for (key, value) in section.iter() {
if key.starts_with("section_") {
if let (sysctl_section, Some(color)) = (
Section::from(key.trim_start_matches("section_").to_string()),
Color::try_from(value).ok(),
) {
self.cli.color.section_colors.insert(sysctl_section, color);
}
}
}
}
if let Some(section) = ini.section(Some("tui")) {
if let Some(tick_rate) = section.get("tick_rate").and_then(|v| v.parse().ok()) {
self.tui.tick_rate = tick_rate;
}
parse_ini_flag!(self, tui, section, no_docs);
}
if let Some(section) = ini.section(Some("tui.colors")) {
if let Some(fg_color) = section.get("fg_color") {
self.tui.color.fg_color = fg_color.to_string();
}
if let Some(bg_color) = section.get("bg_color") {
self.tui.color.bg_color = bg_color.to_string();
}
}
}
Ok(())
}
}
impl Default for Config {
fn default() -> Self {
Self {
verbose: false,
ignore_errors: false,
quiet: false,
no_pager: false,
section_colors: map! {
Section::Abi => Color::Red,
Section::Fs => Color::Green,
Section::Kernel => Color::Magenta,
Section::Net => Color::Blue,
Section::Sunrpc => Color::Yellow,
Section::User => Color::Cyan,
Section::Vm => Color::BrightRed,
Section::Unknown => Color::White
display_deprecated: false,
kernel_docs: None,
cli: CliConfig {
verbose: false,
ignore_errors: false,
quiet: false,
no_pager: false,
display_type: DisplayType::Default,
output_type: OutputType::Default,
color: CliColorConfig {
default_color: Color::BrightBlack,
section_colors: map! {
Section::Abi => Color::Red,
Section::Fs => Color::Green,
Section::Kernel => Color::Magenta,
Section::Net => Color::Blue,
Section::Sunrpc => Color::Yellow,
Section::User => Color::Cyan,
Section::Vm => Color::BrightRed,
Section::Unknown => Color::White
},
},
},
tui: TuiConfig {
tick_rate: 250,
no_docs: false,
color: TuiColorConfig {
fg_color: String::from("white"),
bg_color: String::from("black"),
},
},
default_color: Color::BrightBlack,
display_type: DisplayType::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config() -> Result<()> {
let mut config = Config {
display_deprecated: true,
..Default::default()
};
config.cli.display_type = DisplayType::Value;
config.cli.color.default_color = Color::Blue;
config.cli.color.section_colors = HashMap::new();
config.tui.tick_rate = 3000;
config.tui.color.fg_color = String::new();
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("parent directory not found")
.join("config")
.join(DEFAULT_CONFIG);
config.parse(Some(path))?;
assert_eq!(
Config::default().display_deprecated,
config.display_deprecated
);
assert_eq!(
Some(PathBuf::from("/usr/share/doc/linux")),
config.kernel_docs
);
assert_eq!(Config::default().cli.display_type, config.cli.display_type);
assert_eq!(
Config::default().cli.color.default_color,
config.cli.color.default_color
);
assert_eq!(
Config::default().cli.color.section_colors,
config.cli.color.section_colors
);
assert_eq!(Config::default().tui.tick_rate, config.tui.tick_rate);
assert_eq!(
Config::default().tui.color.fg_color,
config.tui.color.fg_color
);
Ok(())
}
}

View File

@ -24,6 +24,9 @@ pub enum Error {
/// Error that may occur while handling sysctl operations.
#[error("sysctl error: `{0}`")]
SysctlError(#[from] sysctl::SysctlError),
/// Error that may occur while parsing an INI document.
#[error("INI parsing error: `{0}`")]
IniError(#[from] ini::Error),
}
/// Type alias for the standard [`Result`] type.

View File

@ -4,12 +4,13 @@ use crate::error::Result;
use crate::parsers::{parse_kernel_docs, KERNEL_DOCS_PATH};
use crate::sysctl::parameter::Parameter;
use crate::sysctl::section::Section;
use crate::sysctl::DEPRECATED_PARAMS;
use crate::sysctl::{DISABLE_CACHE_ENV, PARAMETERS_CACHE_LABEL, PROC_PATH};
use parseit::globwalk;
use rayon::prelude::*;
use std::convert::TryFrom;
use std::env;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::result::Result as StdResult;
use sysctl::{CtlFlags, CtlIter, Sysctl as SysctlImpl};
@ -33,10 +34,20 @@ impl Sysctl {
}) {
match Parameter::try_from(&ctl) {
Ok(parameter) => {
parameters.push(parameter);
if !config.display_deprecated {
let mut skip_param = false;
if let Some(param_name) = parameter.get_absolute_name() {
skip_param = DEPRECATED_PARAMS.contains(&param_name);
}
if !skip_param {
parameters.push(parameter);
}
} else {
parameters.push(parameter);
}
}
Err(e) => {
if config.verbose {
if config.cli.verbose {
eprintln!("{} ({})", e, ctl.name()?);
}
}
@ -48,21 +59,22 @@ impl Sysctl {
/// Returns the first found parameter in the available parameters.
#[cfg(test)]
fn get_parameter(&self, query: &str) -> Option<&Parameter> {
self.get_parameters(query).first().map(|v| *v)
self.get_parameters(query).first().copied()
}
/// Returns the parameters that matches the given query.
pub fn get_parameters(&self, query: &str) -> Vec<&Parameter> {
let query = query.replace('/', ".");
let parameters = self
.parameters
.iter()
.filter(|param| {
param.name == query.replace('/', ".")
|| param.section.to_string() == query
|| param.get_absolute_name() == Some(&query.replace('/', "."))
param.name == query
|| param.get_absolute_name() == Some(&query)
|| param.is_in_section(&query)
})
.collect::<Vec<&Parameter>>();
if parameters.is_empty() && !self.config.ignore_errors {
if parameters.is_empty() && !self.config.cli.ignore_errors {
eprintln!(
"{}: cannot stat {}{}: No such file or directory",
env!("CARGO_PKG_NAME").split('-').collect::<Vec<_>>()[0],
@ -74,12 +86,8 @@ impl Sysctl {
}
/// Updates the descriptions of the kernel parameters using the given cached data.
pub fn update_docs_from_cache(
&mut self,
kernel_docs: Option<&PathBuf>,
cache: &Cache,
) -> Result<()> {
let mut kernel_docs_path = if let Some(path) = kernel_docs {
pub fn update_docs_from_cache(&mut self, cache: &Cache) -> Result<()> {
let mut kernel_docs_path = if let Some(path) = &self.config.kernel_docs {
vec![path.to_path_buf()]
} else {
Vec::new()
@ -119,17 +127,17 @@ impl Sysctl {
/// Updates the parameters internally using the given list.
///
/// Keeps the original values.
fn update_params(&mut self, mut parameters: Vec<Parameter>) {
parameters.par_iter_mut().for_each(|parameter| {
if let Some(param) = self
.parameters
fn update_params(&mut self, parameters: Vec<Parameter>) {
self.parameters.par_iter_mut().for_each(|parameter| {
if let Some(param) = parameters
.par_iter()
.find_any(|param| param.name == parameter.name)
{
parameter.value = param.value.to_string();
parameter.description = param.description.clone();
parameter.docs_path = param.docs_path.clone();
parameter.docs_title = param.docs_title.clone();
}
});
self.parameters = parameters;
}
/// Updates the descriptions of the kernel parameters.
@ -178,21 +186,27 @@ mod tests {
assert!(sysctl.get_parameter("kernel.hostname").is_some());
assert!(sysctl.get_parameter("unexisting.param").is_none());
assert_eq!(
"Linux",
sysctl.get_parameters("ostype").first().unwrap().value
Some(String::from("Linux")),
sysctl
.get_parameters("ostype")
.first()
.map(|v| v.value.to_string())
);
assert!(sysctl.get_parameters("---").is_empty());
sysctl.update_docs_from_cache(None, &Cache::init()?)?;
sysctl.update_docs_from_cache(&Cache::init()?)?;
let parameter = sysctl.get_parameter("kernel.hostname").unwrap().clone();
let parameter = sysctl
.get_parameter("kernel.hostname")
.expect("failed to get parameter")
.clone();
let old_value = parameter.docs_title;
let parameters = sysctl.parameters.clone();
sysctl
.parameters
.iter_mut()
.find(|param| param.name == parameter.name)
.unwrap()
.expect("parameter not found")
.docs_title = String::from("-");
sysctl.update_params(parameters);
assert_eq!(
@ -201,24 +215,24 @@ mod tests {
.parameters
.iter_mut()
.find(|param| param.name == parameter.name)
.unwrap()
.expect("parameter not found")
.docs_title
);
assert!(sysctl
.get_parameter("vm.zone_reclaim_mode")
.unwrap()
.expect("failed to get parameter")
.description
.as_ref()
.unwrap()
.expect("parameter has no description")
.contains("zone_reclaim_mode is disabled by default."));
assert!(sysctl
.get_parameter("user.max_user_namespaces")
.unwrap()
.expect("failed to get parameter")
.description
.as_ref()
.unwrap()
.expect("parameter has no description")
.contains("The maximum number of user namespaces"));
Ok(())

View File

@ -1,18 +0,0 @@
/// Possible ways of displaying the kernel parameters.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DisplayType {
/// Print the kernel parameter name along with its value.
Default,
/// Print only the name of the parameter.
Name,
/// Print only the value of the parameter.
Value,
/// Print only the value of the parameter without new line.
Binary,
}
impl Default for DisplayType {
fn default() -> Self {
Self::Default
}
}

View File

@ -4,8 +4,8 @@ pub mod controller;
/// Sysctl section.
pub mod section;
/// Sysctl display options.
pub mod display;
/// Sysctl display/output options.
pub mod r#type;
/// Kernel parameter.
pub mod parameter;

View File

@ -1,9 +1,10 @@
use crate::config::Config;
use crate::error::Result;
use crate::sysctl::display::DisplayType;
use crate::sysctl::r#type::DisplayType;
use crate::sysctl::section::Section;
use colored::*;
use serde::{Deserialize, Serialize};
use std::fmt::Write as _;
use std::io::Write;
use std::path::PathBuf;
use sysctl::{Ctl, Sysctl as SysctlImpl};
@ -52,19 +53,22 @@ impl Parameter {
/// Returns the parameter name with corresponding section colors.
pub fn get_colored_name(&self, config: &Config) -> String {
let section_color = *(config
.cli
.color
.section_colors
.get(&self.section)
.unwrap_or(&config.default_color));
.unwrap_or(&config.cli.color.default_color));
let fields = self.name.split('.').collect::<Vec<&str>>();
fields
.iter()
.enumerate()
.fold(String::new(), |mut result, (i, v)| {
if i != fields.len() - 1 {
result += &format!(
let _ = write!(
result,
"{}{}",
v.color(section_color),
".".color(config.default_color)
".".color(config.cli.color.default_color)
);
} else {
result += v;
@ -73,14 +77,16 @@ impl Parameter {
})
}
/// Returns the components of the parameter to contruct a [`Tree`].
/// Returns the components of the parameter to construct a [`Tree`].
///
/// [`Tree`]: crate::tree::Tree
pub fn get_tree_components(&self, config: &Config) -> Vec<String> {
let section_color = *(config
.cli
.color
.section_colors
.get(&self.section)
.unwrap_or(&config.default_color));
.unwrap_or(&config.cli.color.default_color));
let mut components = self
.name
.split('.')
@ -93,11 +99,11 @@ impl Parameter {
.for_each(|(i, component)| {
if i != total_components - 1 {
*component = component.color(section_color).to_string();
} else if config.display_type != DisplayType::Name {
} else if config.cli.display_type != DisplayType::Name {
*component = format!(
"{} {} {}",
component,
"=".color(config.default_color),
"=".color(config.cli.color.default_color),
self.value.replace('\n', " ").bold()
);
}
@ -107,7 +113,7 @@ impl Parameter {
/// Prints the kernel parameter to given output.
pub fn display_value<Output: Write>(&self, config: &Config, output: &mut Output) -> Result<()> {
match config.display_type {
match config.cli.display_type {
DisplayType::Name => {
writeln!(output, "{}", self.get_colored_name(config))?;
}
@ -123,7 +129,7 @@ impl Parameter {
output,
"{} {} {}",
self.get_colored_name(config),
"=".color(config.default_color),
"=".color(config.cli.color.default_color),
value.bold(),
)?;
}
@ -185,11 +191,27 @@ impl Parameter {
let ctl = Ctl::new(&self.name)?;
let new_value = ctl.set_value_string(new_value)?;
self.value = new_value;
if !config.quiet {
if !config.cli.quiet {
self.display_value(config, output)?;
}
Ok(())
}
/// Performs a search for given query and returns true if
/// the parameter is in the given sub/section.
pub fn is_in_section(&self, query: &str) -> bool {
let mut subsection = self.section.to_string();
let mut components = self.name.split('.').skip(1).peekable();
while let Some(component) = components.next() {
if query == subsection {
return true;
}
if components.peek().is_some() {
subsection = format!("{}.{}", subsection, component)
}
}
false
}
}
#[cfg(test)]
@ -208,9 +230,16 @@ mod tests {
};
assert_eq!(Some("test_param"), parameter.get_absolute_name());
let mut config = Config::default();
config.default_color = Color::White;
*(config.section_colors.get_mut(&Section::Kernel).unwrap()) = Color::Yellow;
let mut config = Config {
..Default::default()
};
config.cli.color.default_color = Color::White;
*(config
.cli
.color
.section_colors
.get_mut(&Section::Kernel)
.expect("failed to get color")) = Color::Yellow;
assert_eq!(parameter.name, parameter.get_colored_name(&config));
assert_eq!(
@ -230,7 +259,7 @@ mod tests {
);
output.clear();
config.display_type = DisplayType::Name;
config.cli.display_type = DisplayType::Name;
parameter.display_value(&config, &mut output)?;
assert_eq!(
"kernel.fictional.test_param\n",
@ -238,12 +267,12 @@ mod tests {
);
output.clear();
config.display_type = DisplayType::Value;
config.cli.display_type = DisplayType::Value;
parameter.display_value(&config, &mut output)?;
assert_eq!("1\n", String::from_utf8_lossy(&output));
output.clear();
config.display_type = DisplayType::Binary;
config.cli.display_type = DisplayType::Binary;
parameter.display_value(&config, &mut output)?;
assert_eq!("1", String::from_utf8_lossy(&output));
@ -275,6 +304,19 @@ mod tests {
.update_value("0", &config, &mut Vec::new())
.is_err());
parameter.name = String::from("kernel.fictional.testing.xyz.parameter");
assert!(parameter.is_in_section(&parameter.section.to_string()));
assert!(parameter.is_in_section("kernel"));
assert!(parameter.is_in_section("kernel.fictional"));
assert!(parameter.is_in_section("kernel.fictional.testing"));
assert!(parameter.is_in_section("kernel.fictional.testing.xyz"));
assert!(!parameter.is_in_section("xyz"));
assert!(!parameter.is_in_section("test"));
assert!(!parameter.is_in_section("ker"));
assert!(!parameter.is_in_section("kernel.fi"));
assert!(!parameter.is_in_section("kernel.fictional.tes"));
assert!(!parameter.is_in_section(&parameter.name));
Ok(())
}
}

View File

@ -0,0 +1,73 @@
/// Macro for generating enum type with a Default variant and common implementations.
macro_rules! gen_type_property {
($name: ident,
$($variant: ident,)+
) => {
/// Enum containing variants.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum $name {
/// Default variant.
Default,
$(
/// Variant.
$variant
),+
}
impl<'a> From<&'a str> for $name {
fn from(value: &'a str) -> Self {
for section in Self::variants() {
if value.to_lowercase() == section.to_string() {
return *section;
}
}
Self::Default
}
}
impl Default for $name {
fn default() -> Self {
Self::Default
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", format!("{:?}", self).to_lowercase())
}
}
impl $name {
/// Returns the variants.
pub fn variants() -> &'static [Self] {
&[Self::Default, $(Self::$variant),+]
}
}
};
}
gen_type_property!(DisplayType, Name, Value, Binary,);
gen_type_property!(OutputType, Tree, Json,);
#[cfg(test)]
mod tests {
#[test]
fn test_gen_type() {
gen_type_property!(TestType, One, Two, Three,);
assert_eq!(TestType::Two, TestType::from("two"));
assert_eq!(TestType::Two, TestType::from("TwO"));
assert_eq!(TestType::Default, TestType::from("tw0"));
assert_eq!(TestType::Default, TestType::default());
assert_eq!("three", &TestType::Three.to_string());
assert_eq!("one", &TestType::One.to_string());
assert_eq!(
&[
TestType::Default,
TestType::One,
TestType::Two,
TestType::Three
],
TestType::variants()
);
}
}

View File

@ -220,12 +220,12 @@ mod tests {
}
#[test]
fn test_tree_output() {
fn test_tree_output() -> IoResult<()> {
let lines = ["a", "a/b/e", "a/b", "a/b/c/d"];
let tree = Tree::from_input(&mut lines.iter(), '/');
let mut output = Vec::new();
tree.print(&mut output, Color::White).unwrap();
tree.print(&mut output, Color::White)?;
let expected_output = "\
a
@ -235,10 +235,12 @@ a
d\n";
assert_eq!(expected_output, String::from_utf8_lossy(&output));
Ok(())
}
#[test]
fn test_print_line() {
fn test_print_line() -> IoResult<()> {
let value = String::from("abc\ndef");
let mut output = Vec::new();
@ -246,8 +248,7 @@ a
value: value.to_string(),
childs: Vec::new(),
}
.print_line(&mut output, &[], Color::White)
.unwrap();
.print_line(&mut output, &[], Color::White)?;
assert_eq!(b"abc\ndef\n", &*output);
let mut output = Vec::new();
@ -255,17 +256,17 @@ a
value: value.to_string(),
childs: Vec::new(),
}
.print_line(&mut output, &[true, false, true], Color::White)
.unwrap();
.print_line(&mut output, &[true, false, true], Color::White)?;
assert_eq!(" │ └── abc\ndef\n".as_bytes(), &*output);
let mut output = Vec::new();
TreeNode {
value: value.to_string(),
value,
childs: Vec::new(),
}
.print_line(&mut output, &[true, false, false], Color::White)
.unwrap();
.print_line(&mut output, &[true, false, false], Color::White)?;
assert_eq!(" │ ├── abc\ndef\n".as_bytes(), &*output);
Ok(())
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "systeroid-tui"
version = "0.1.1" # managed by release.sh
version = "0.2.1" # managed by release.sh
description = "A terminal user interface for managing kernel parameters"
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
license = "MIT OR Apache-2.0"
@ -10,7 +10,7 @@ repository = "https://github.com/orhun/systeroid"
keywords = ["linux", "kernel", "parameter", "sysctl", "tui"]
categories = ["command-line-utilities"]
edition = "2021"
rust-version = "1.56.1"
rust-version = "1.57.0"
[features]
# clipboard support is enabled as default
@ -20,16 +20,22 @@ clipboard = ["copypasta-ext"]
[dependencies]
termion = "1.5.6"
unicode-width = "0.1.9"
thiserror = "1.0.30"
thiserror = "1.0.34"
getopts = "0.2.21"
copypasta-ext = { version = "0.3.7", optional = true }
colorsys = "0.6.5"
colorsys = "0.6.6"
[dependencies.systeroid-core]
version = "0.1.1" # managed by release.sh
version = "0.2.1" # managed by release.sh
path = "../systeroid-core"
[dependencies.tui]
version = "0.18.0"
version = "0.19.0"
default-features = false
features = ["termion"]
# metadata for cargo-binstall to get the right artifacts
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/systeroid-{ version }-{ target }.{ archive-format }"
bin-dir = "systeroid-{ version }/{ bin }{ binary-ext }"
pkg-fmt = "tgz"

View File

@ -1,7 +1,7 @@
use crate::style::Colors;
use getopts::Options;
use std::env;
use std::path::PathBuf;
use systeroid_core::config::CONFIG_ENV;
use systeroid_core::sysctl::section::Section;
use systeroid_core::sysctl::KERNEL_DOCS_ENV;
@ -18,6 +18,8 @@ For more details see {bin}(8)."#;
/// Command-line arguments.
#[derive(Debug, Default)]
pub struct Args {
/// Location of the configuration file.
pub config: Option<PathBuf>,
/// Refresh rate of the terminal.
pub tick_rate: u64,
/// Path of the Linux kernel documentation.
@ -26,10 +28,14 @@ pub struct Args {
pub section: Option<Section>,
/// Query to search on startup.
pub search_query: Option<String>,
/// Background/foreground colors.
pub colors: Colors,
/// Foreground color.
pub fg_color: String,
/// Background color.
pub bg_color: String,
/// Do not parse/show Linux kernel documentation.
pub no_docs: bool,
/// Whether if the deprecated variables should be included while listing.
pub display_deprecated: bool,
}
impl Args {
@ -63,6 +69,17 @@ impl Args {
"<color>",
);
opts.optflag("n", "no-docs", "do not show the kernel documentation");
opts.optflag(
"",
"deprecated",
"include deprecated variables while listing",
);
opts.optopt(
"c",
"config",
"set the path of the configuration file",
"<path>",
);
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
opts
@ -99,13 +116,18 @@ impl Args {
.map(PathBuf::from),
section: matches.opt_str("s").map(Section::from),
search_query: matches.opt_str("q"),
colors: Colors::new(
matches.opt_str("bg-color").as_deref().unwrap_or("black"),
matches.opt_str("fg-color").as_deref().unwrap_or("white"),
)
.map_err(|e| eprintln!("error: `{}`", e))
.ok()?,
fg_color: matches
.opt_str("fg-color")
.unwrap_or_else(|| String::from("white")),
bg_color: matches
.opt_str("bg-color")
.unwrap_or_else(|| String::from("black")),
no_docs: matches.opt_present("n"),
display_deprecated: matches.opt_present("deprecated"),
config: matches
.opt_str("c")
.or_else(|| env::var(CONFIG_ENV).ok())
.map(PathBuf::from),
})
}
}
@ -136,7 +158,7 @@ mod tests {
String::from("-q"),
String::from("test"),
])
.unwrap();
.expect("failed to parse arguments");
assert_eq!(1000, args.tick_rate);
assert_eq!(Some(PathBuf::from("/docs")), args.kernel_docs);

View File

@ -3,7 +3,7 @@ use std::str::FromStr;
use termion::event::Key;
/// Possible application commands.
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
/// Show help.
Help,
@ -47,17 +47,14 @@ impl FromStr for Command {
"exit" | "quit" | "q" | "q!" => Ok(Command::Exit),
_ => {
if s.starts_with("set") {
let values: Vec<&str> = s
.trim_start_matches("set")
.trim()
.split_whitespace()
.collect();
let values: Vec<&str> =
s.trim_start_matches("set").split_whitespace().collect();
Ok(Command::Set(
values.first().ok_or(())?.to_string(),
values[1..].join(" "),
))
} else if s.starts_with("scroll") {
let mut values = s.trim_start_matches("scroll").trim().split_whitespace();
let mut values = s.trim_start_matches("scroll").split_whitespace();
Ok(Command::Scroll(
ScrollArea::try_from(values.next().ok_or(())?)?,
Direction::try_from(values.next().ok_or(())?)?,
@ -157,7 +154,7 @@ mod tests {
"scroll list bottom 1",
),
] {
assert_eq!(command, Command::from_str(value).unwrap());
assert_eq!(Ok(command), Command::from_str(value));
}
assert!(Command::from_str("---").is_err());
assert_command_parser! {

View File

@ -58,13 +58,14 @@ impl EventHandler {
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Result;
use std::char;
use std::time::Instant;
const TICK_RATE_MS: u64 = 100;
#[test]
fn test_event() {
fn test_event() -> Result<()> {
let start_time = Instant::now();
let event_handler = EventHandler::new(TICK_RATE_MS);
let mut tick_count = 0;
@ -73,9 +74,9 @@ mod tests {
thread::spawn(move || {
let key = Key::Char(char::from_digit(i, 10).unwrap_or('9'));
let event = Event::KeyPress(key);
sender.send(event).unwrap();
sender.send(event).expect("failed to send event");
});
match event_handler.next().unwrap() {
match event_handler.next()? {
Event::KeyPress(key) => {
if key == Key::Char('9') {
break;
@ -88,5 +89,6 @@ mod tests {
}
}
assert!(start_time.elapsed() > Duration::from_millis(tick_count * TICK_RATE_MS));
Ok(())
}
}

View File

@ -26,6 +26,7 @@ use crate::args::Args;
use crate::command::Command;
use crate::error::Result;
use crate::event::{Event, EventHandler};
use crate::style::Colors;
use systeroid_core::cache::Cache;
use systeroid_core::config::Config;
use systeroid_core::sysctl::controller::Sysctl;
@ -34,14 +35,25 @@ use tui::terminal::Terminal;
/// Runs `systeroid-tui`.
pub fn run<B: Backend>(args: Args, backend: B) -> Result<()> {
let mut sysctl = Sysctl::init(Config::default())?;
if !args.no_docs {
sysctl.update_docs_from_cache(args.kernel_docs.as_ref(), &Cache::init()?)?;
let mut config = Config {
display_deprecated: args.display_deprecated,
kernel_docs: args.kernel_docs,
..Default::default()
};
config.tui.tick_rate = args.tick_rate;
config.tui.no_docs = args.no_docs;
config.tui.color.fg_color = args.fg_color;
config.tui.color.bg_color = args.bg_color;
config.parse(args.config)?;
let colors = Colors::new(&config.tui.color.bg_color, &config.tui.color.fg_color)?;
let mut sysctl = Sysctl::init(config)?;
if !sysctl.config.tui.no_docs {
sysctl.update_docs_from_cache(&Cache::init()?)?;
}
let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor()?;
terminal.clear()?;
let event_handler = EventHandler::new(args.tick_rate);
let event_handler = EventHandler::new(sysctl.config.tui.tick_rate);
let mut app = App::new(&mut sysctl);
if let Some(section) = args.section {
app.section_list.state.select(Some(
@ -59,7 +71,7 @@ pub fn run<B: Backend>(args: Args, backend: B) -> Result<()> {
app.input = None;
}
while app.running {
terminal.draw(|frame| ui::render(frame, &mut app, &args.colors))?;
terminal.draw(|frame| ui::render(frame, &mut app, &colors))?;
match event_handler.next()? {
Event::KeyPress(key) => {
let command = Command::parse(key, app.is_input_mode());
@ -87,6 +99,8 @@ mod tests {
fn test_systeroid_tui() -> Result<()> {
let args = Args {
tick_rate: 1000,
fg_color: String::from("white"),
bg_color: String::from("black"),
..Args::default()
};
let backend = TestBackend::new(40, 10);

View File

@ -5,7 +5,7 @@ macro_rules! generate_option {
$($variant: ident => $str_repr: expr,)+
) => {
/// Available options.
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum $name {
$(
/// Option.

View File

@ -5,7 +5,7 @@ use std::str::FromStr;
use tui::style::{Color as TuiColor, Style};
/// Color configuration.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Colors {
/// Background color.
bg: Color,
@ -39,7 +39,7 @@ impl Colors {
}
/// Wrapper for widget colors.
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Color {
/// Inner type.
inner: TuiColor,
@ -76,13 +76,13 @@ impl FromStr for Color {
"magenta" => TuiColor::Magenta,
"cyan" => TuiColor::Cyan,
"gray" => TuiColor::Gray,
"darkgray" => TuiColor::DarkGray,
"lightred" => TuiColor::LightRed,
"lightgreen" => TuiColor::LightGreen,
"lightyellow" => TuiColor::LightYellow,
"lightblue" => TuiColor::LightBlue,
"lightmagenta" => TuiColor::LightMagenta,
"lightcyan" => TuiColor::LightCyan,
"darkgray" | "dark gray" => TuiColor::DarkGray,
"lightred" | "light red" => TuiColor::LightRed,
"lightgreen" | "light green" => TuiColor::LightGreen,
"lightyellow" | "light yellow" => TuiColor::LightYellow,
"lightblue" | "light blue" => TuiColor::LightBlue,
"lightmagenta" | "light magenta" => TuiColor::LightMagenta,
"lightcyan" | "light cyan" => TuiColor::LightCyan,
"white" => TuiColor::White,
_ => {
let rgb = Rgb::from_hex_str(&format!("#{}", s))?;
@ -102,6 +102,8 @@ mod tests {
assert_eq!(TuiColor::Gray, Color::from_str("gray")?.get());
assert_eq!(TuiColor::Black, Color::from_str("black")?.get());
assert_eq!(TuiColor::Green, Color::from_str("green")?.get());
assert_eq!(TuiColor::LightRed, Color::from_str("light red")?.get());
assert_eq!(TuiColor::LightBlue, Color::from_str("lightblue")?.get());
assert_eq!(
TuiColor::Rgb(152, 157, 69),
Color::from_str("989D45")?.get()

View File

@ -1,6 +1,6 @@
[package]
name = "systeroid"
version = "0.1.1" # managed by release.sh
version = "0.2.1" # managed by release.sh
description = "A more powerful alternative to sysctl"
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
license = "MIT OR Apache-2.0"
@ -21,5 +21,11 @@ live-tests = []
getopts = "0.2.21"
[dependencies.systeroid-core]
version = "0.1.1" # managed by release.sh
version = "0.2.1" # managed by release.sh
path = "../systeroid-core"
# metadata for cargo-binstall to get the right artifacts
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ version }-{ target }.{ archive-format }"
bin-dir = "{ name }-{ version }/{ bin }{ binary-ext }"
pkg-fmt = "tgz"

View File

@ -1,4 +1,3 @@
use crate::output::OutputType;
use std::env;
use std::io::{self, BufRead, Write};
use std::path::PathBuf;
@ -9,6 +8,7 @@ use systeroid_core::parseit::reader;
use systeroid_core::parseit::regex::Regex;
use systeroid_core::sysctl::controller::Sysctl;
use systeroid_core::sysctl::parameter::Parameter;
use systeroid_core::sysctl::r#type::OutputType;
use systeroid_core::sysctl::{DEPRECATED_PARAMS, SYSTEM_PRELOAD};
use systeroid_core::tree::{Tree, TreeNode};
@ -19,18 +19,12 @@ pub struct App<'a, Output: Write> {
sysctl: &'a mut Sysctl,
/// Standard output.
output: &'a mut Output,
/// Output type.
output_type: OutputType,
}
impl<'a, Output: Write> App<'a, Output> {
/// Constructs a new instance.
pub fn new(sysctl: &'a mut Sysctl, output: &'a mut Output, output_type: OutputType) -> Self {
Self {
sysctl,
output,
output_type,
}
pub fn new(sysctl: &'a mut Sysctl, output: &'a mut Output) -> Self {
Self { sysctl, output }
}
/// Prints the given parameters to stdout.
@ -38,7 +32,7 @@ impl<'a, Output: Write> App<'a, Output> {
where
I: Iterator<Item = &'b Parameter>,
{
match self.output_type {
match self.sysctl.config.cli.output_type {
OutputType::Default => {
parameters.try_for_each(|parameter| {
parameter.display_value(&self.sysctl.config, self.output)
@ -54,7 +48,8 @@ impl<'a, Output: Write> App<'a, Output> {
.map(|v| v.as_ref()),
);
});
Tree::new(root_node.childs).print(self.output, self.sysctl.config.default_color)?;
Tree::new(root_node.childs)
.print(self.output, self.sysctl.config.cli.color.default_color)?;
}
OutputType::Json => {
Parameter::display_bulk_json(parameters.collect(), self.output)?;
@ -64,22 +59,12 @@ impl<'a, Output: Write> App<'a, Output> {
}
/// Displays all of the available kernel parameters.
pub fn display_parameters(
&mut self,
pattern: Option<Regex>,
display_deprecated: bool,
explain: bool,
) -> Result<()> {
pub fn display_parameters(&mut self, pattern: Option<Regex>, explain: bool) -> Result<()> {
let parameters = self.sysctl.parameters.clone();
let mut parameters = parameters.iter().filter(|parameter| {
if let Some(pattern) = &pattern {
return pattern.is_match(&parameter.name);
}
if !display_deprecated {
if let Some(param_name) = parameter.get_absolute_name() {
return !DEPRECATED_PARAMS.contains(&param_name);
}
}
true
});
if explain {
@ -91,7 +76,7 @@ impl<'a, Output: Write> App<'a, Output> {
/// Displays the documentation of a parameter.
pub fn display_documentation(&mut self, param_name: &str) -> Result<()> {
let no_pager = self.sysctl.config.no_pager;
let no_pager = self.sysctl.config.cli.no_pager;
for parameter in self.sysctl.get_parameters(param_name) {
let mut fallback_to_default = false;
if no_pager {
@ -182,7 +167,9 @@ impl<'a, Output: Write> App<'a, Output> {
/// Processes the parameters in the given file.
pub fn preload_from_file(&mut self, path: PathBuf) -> Result<()> {
if path == PathBuf::from("-") {
for line in io::stdin().lock().lines() {
let stdin = io::stdin();
let lines = stdin.lock().lines();
for line in lines {
if let Err(e) = self.process_parameter(line?, true, false) {
println!("{}: {}", env!("CARGO_PKG_NAME"), e);
}
@ -239,22 +226,21 @@ mod tests {
#[test]
fn test_app() -> Result<()> {
let mut output = Vec::new();
let mut sysctl = Sysctl::init(Config {
no_pager: true,
..Config::default()
})?;
sysctl.update_docs_from_cache(None, &Cache::init()?)?;
let mut config = Config::default();
config.cli.no_pager = true;
let mut sysctl = Sysctl::init(config)?;
sysctl.update_docs_from_cache(&Cache::init()?)?;
let mut app = App::new(&mut sysctl, &mut output, OutputType::Default);
let mut app = App::new(&mut sysctl, &mut output);
app.display_parameters(Regex::new("kernel|vm").ok(), false, false)?;
app.display_parameters(Regex::new("kernel|vm").ok(), false)?;
let result = String::from_utf8_lossy(app.output);
assert!(result.contains("vm.zone_reclaim_mode ="));
assert!(result.contains("kernel.version ="));
app.output.clear();
app.output_type = OutputType::Tree;
app.display_parameters(None, true, false)?;
app.sysctl.config.cli.output_type = OutputType::Tree;
app.display_parameters(None, false)?;
assert!(String::from_utf8_lossy(app.output).contains("─ osrelease ="));
app.output.clear();
@ -263,7 +249,7 @@ mod tests {
app.output.clear();
let param_name = String::from("kernel.version");
app.output_type = OutputType::Default;
app.sysctl.config.cli.output_type = OutputType::Default;
app.process_parameter(param_name.clone(), true, false)?;
let result = String::from_utf8_lossy(app.output);
assert_eq!(1, result.lines().count());
@ -271,7 +257,7 @@ mod tests {
app.output.clear();
let param_name = String::from("kernel.version");
app.output_type = OutputType::Json;
app.sysctl.config.cli.output_type = OutputType::Json;
app.process_parameter(param_name.clone(), true, false)?;
let result = String::from_utf8_lossy(app.output);
assert!(result.contains("\"section\":\"kernel\""));

View File

@ -1,9 +1,10 @@
use crate::output::OutputType;
use getopts::Options;
use std::env;
use std::path::PathBuf;
use systeroid_core::config::CONFIG_ENV;
use systeroid_core::parseit::regex::Regex;
use systeroid_core::sysctl::display::DisplayType;
use systeroid_core::sysctl::r#type::DisplayType;
use systeroid_core::sysctl::r#type::OutputType;
use systeroid_core::sysctl::{DEFAULT_PRELOAD, KERNEL_DOCS_ENV};
/// Help message for the arguments.
@ -19,6 +20,8 @@ For more details see {bin}(8)."#;
/// Command-line arguments.
#[derive(Debug, Default)]
pub struct Args {
/// Location of the configuration file.
pub config: Option<PathBuf>,
/// Whether if the verbose logging is enabled.
pub verbose: bool,
/// Whether if the quiet mode is enabled.
@ -97,6 +100,12 @@ impl Args {
opts.optflag("P", "no-pager", "do not pipe output into a pager");
opts.optflag("v", "verbose", "enable verbose logging");
opts.optflag("", "tui", "show terminal user interface");
opts.optopt(
"c",
"config",
"set the path of the configuration file",
"<path>",
);
opts.optflag("h", "help", "display this help and exit (-d)");
opts.optflag("V", "version", "output version information and exit");
opts
@ -195,6 +204,10 @@ impl Args {
explain: matches.opt_present("E"),
output_type,
show_tui: matches.opt_present("tui"),
config: matches
.opt_str("c")
.or_else(|| env::var(CONFIG_ENV).ok())
.map(PathBuf::from),
values: matches.free,
})
}
@ -222,20 +235,20 @@ mod tests {
String::from("-A"),
String::from("-T"),
])
.unwrap();
.expect("failed to parse arguments");
assert!(args.verbose);
assert!(args.write);
assert_eq!(OutputType::Tree, args.output_type);
assert!(!Args::parse(vec![String::new(), String::from("-p")])
.unwrap()
.expect("failed to parse arguments")
.values
.is_empty());
assert_eq!(
DisplayType::Binary,
Args::parse(vec![String::new(), String::from("-A"), String::from("-b")])
.unwrap()
.expect("failed to parse arguments")
.display_type
);
}

View File

@ -6,8 +6,6 @@
pub mod app;
/// Command-line argument parser.
pub mod args;
/// Application output types.
pub mod output;
use crate::app::App;
use crate::args::Args;
@ -20,24 +18,28 @@ use systeroid_core::sysctl::controller::Sysctl;
/// Runs `systeroid`.
pub fn run<Output: Write>(args: Args, output: &mut Output) -> Result<()> {
let config = Config {
verbose: args.verbose,
ignore_errors: args.ignore_errors,
quiet: args.quiet,
no_pager: args.no_pager,
display_type: args.display_type,
let mut config = Config {
display_deprecated: args.display_deprecated,
kernel_docs: args.kernel_docs,
..Default::default()
};
config.cli.verbose = args.verbose;
config.cli.ignore_errors = args.ignore_errors;
config.cli.quiet = args.quiet;
config.cli.no_pager = args.no_pager;
config.cli.display_type = args.display_type;
config.cli.output_type = args.output_type;
config.parse(args.config)?;
let mut sysctl = Sysctl::init(config)?;
if args.explain {
sysctl.update_docs_from_cache(args.kernel_docs.as_ref(), &Cache::init()?)?;
sysctl.update_docs_from_cache(&Cache::init()?)?;
}
let mut app = App::new(&mut sysctl, output, args.output_type);
let mut app = App::new(&mut sysctl, output);
if args.preload_system_files {
app.preload_from_system()?;
} else if args.values.is_empty() {
app.display_parameters(args.pattern, args.display_deprecated, args.explain)?;
app.display_parameters(args.pattern, args.explain)?;
} else if args.explain {
for param in args.values {
app.display_documentation(&param)?;

View File

@ -8,6 +8,9 @@ fn main() {
if args.show_tui {
let bin = format!("{}-tui", env!("CARGO_PKG_NAME"));
let mut command = Command::new(&bin);
if let Some(config) = args.config {
command.arg("--config").arg(config);
}
if let Some(kernel_docs) = args.kernel_docs {
command.arg("--docs").arg(kernel_docs);
}

View File

@ -1,18 +0,0 @@
/// Possible output types for the [`App`].
///
/// [`App`]: crate::app::App
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OutputType {
/// Print the output as is.
Default,
/// Print the output in a tree-like format.
Tree,
/// Print the output in JSON format.
Json,
}
impl Default for OutputType {
fn default() -> Self {
Self::Default
}
}

View File

@ -1,7 +1,6 @@
use {
systeroid::args::Args, systeroid_core::error::Result,
systeroid_core::sysctl::display::DisplayType,
};
use systeroid::args::Args;
use systeroid_core::error::Result;
use systeroid_core::sysctl::r#type::DisplayType;
#[cfg_attr(not(feature = "live-tests"), ignore)]
#[test]