From 8b056449903f3ed4a69d3b48d4c30a74bc476f73 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 7 Jun 2022 21:53:20 +0200 Subject: [PATCH 1/6] new: change version to 0.11.2-alpha.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffcd7203..43a8a079 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,7 +733,7 @@ dependencies = [ [[package]] name = "hl" -version = "0.11.1" +version = "0.11.2-alpha.0" dependencies = [ "ansi_term", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index f4a49a14..8467b7b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ categories = ["command-line-utilities"] description = "Utility for viewing json-formatted log files." keywords = ["cli", "human", "log"] name = "hl" -version = "0.11.1" +version = "0.11.2-alpha.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From c6a5a7405f14dfc053ea93f5fe88695c558326ac Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 7 Jun 2022 21:51:12 +0200 Subject: [PATCH 2/6] new: upgrade atoi, itoa and enum-map --- Cargo.lock | 14 +++++++------- Cargo.toml | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43a8a079..30a78fc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "atoi" -version = "0.4.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" dependencies = [ "num-traits", ] @@ -590,18 +590,18 @@ dependencies = [ [[package]] name = "enum-map" -version = "1.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e893a7ba6116821058dec84a6fb14fb2a97cd8ce5fd0f85d5a4e760ecd7329d9" +checksum = "1284d66c2ebd284a159491ebc005c6608ef684f4f5db99c960b1837cb74b7067" dependencies = [ "enum-map-derive", ] [[package]] name = "enum-map-derive" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84278eae0af6e34ff6c1db44c11634a694aafac559ff3080e4db4e4ac35907aa" +checksum = "00d1c54e25a57236a790ecf051c2befbb57740c9b86c4273eac378ba84d620d6" dependencies = [ "proc-macro2", "quote", @@ -761,7 +761,7 @@ dependencies = [ "htp", "humantime", "itertools", - "itoa 0.4.8", + "itoa 1.0.2", "num_cpus", "once_cell", "pipe", diff --git a/Cargo.toml b/Cargo.toml index 8467b7b0..8c2b5ae6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] ansi_term = "0" anyhow = "1" -atoi = "0" +atoi = "1" atty = "0" bitmask = "0" bytefmt = "0" @@ -25,7 +25,7 @@ crossbeam-channel = "0" crossbeam-queue = "0" crossbeam-utils = "0" derive_deref = "1" -enum-map = "1" +enum-map = "2" error-chain = "0" flate2 = "1" heapless = "0" @@ -47,7 +47,7 @@ thiserror = "1" wildmatch = "2" [dependencies.itoa] -version = "0" +version = "1" default-features = false [dependencies.clap] From 719f45c802376eb3c13eb1bc1e14920eb89fa4f5 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 7 Jun 2022 21:55:19 +0200 Subject: [PATCH 3/6] new: change edition to 2021 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8c2b5ae6..c50a8adf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ description = "Utility for viewing json-formatted log files." keywords = ["cli", "human", "log"] name = "hl" version = "0.11.2-alpha.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 53020b66e82bf9ed675c38025ed6d458996984b7 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 7 Jun 2022 21:58:32 +0200 Subject: [PATCH 4/6] new: replace structopt with clap 3 --- Cargo.lock | 126 +++++++++++++++++++++++++++++---------------------- Cargo.toml | 5 +- README.md | 60 ++++++++++++------------ src/error.rs | 58 +++++++++++++++--------- src/main.rs | 102 ++++++++++++++++++++--------------------- src/types.rs | 13 +++--- 6 files changed, 196 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30a78fc5..9b7d2f5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,14 +311,49 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "ansi_term", + "bitflags", + "textwrap 0.11.0", + "unicode-width", +] + +[[package]] +name = "clap" +version = "3.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +dependencies = [ "atty", "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "lazy_static", "strsim", - "term_size", - "textwrap", - "unicode-width", - "vec_map", + "termcolor", + "terminal_size", + "textwrap 0.15.0", +] + +[[package]] +name = "clap_derive" +version = "3.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +dependencies = [ + "os_str_bytes", ] [[package]] @@ -390,7 +425,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -715,12 +750,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -744,7 +776,7 @@ dependencies = [ "bytefmt", "chrono", "chrono-tz", - "clap", + "clap 3.1.18", "closure", "collection_macros", "config", @@ -774,7 +806,6 @@ dependencies = [ "shellwords", "signal-hook", "stats_alloc", - "structopt", "thiserror", "wildmatch", "winapi", @@ -1019,6 +1050,12 @@ dependencies = [ "hashbrown 0.12.1", ] +[[package]] +name = "os_str_bytes" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" + [[package]] name = "parse-zoneinfo" version = "0.3.0" @@ -1585,50 +1622,35 @@ checksum = "5c0e04424e733e69714ca1bbb9204c1a57f09f5493439520f9f68c132ad25eec" [[package]] name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.26" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "structopt-derive" -version = "0.4.18" +name = "syn" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ - "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "unicode-ident", ] [[package]] -name = "syn" -version = "1.0.96" +name = "termcolor" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "winapi-util", ] [[package]] -name = "term_size" -version = "0.3.2" +name = "terminal_size" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" dependencies = [ "libc", "winapi", @@ -1640,10 +1662,18 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "term_size", "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +dependencies = [ + "terminal_size", +] + [[package]] name = "thiserror" version = "1.0.31" @@ -1720,12 +1750,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - [[package]] name = "unicode-width" version = "0.1.9" @@ -1738,12 +1762,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index c50a8adf..a86534a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,6 @@ serde_json = { version = "1", features = ["raw_value"] } serde_yaml = "0" shellwords = "1" signal-hook = "0" -structopt = "0" thiserror = "1" wildmatch = "2" @@ -51,8 +50,8 @@ version = "1" default-features = false [dependencies.clap] -version = "2" -features = ["wrap_help"] +version = "3" +features = ["wrap_help", "derive", "env"] [dependencies.winapi] version = "0" diff --git a/README.md b/README.md index 01a3c67a..1420e49c 100644 --- a/README.md +++ b/README.md @@ -297,43 +297,41 @@ Log viewer which translates JSON logs into pretty human-readable representation. ### Complete set of options and flags ``` -hl 0.10.3 +hl 0.11.0 JSON log converter to human readable representation USAGE: - hl [FLAGS] [OPTIONS] [--] [FILE]... - -FLAGS: - -c Handful alias for --color=always, overrides --color option - --help Prints help information - --list-themes List available themes and exit - -L, --local Use local time zone, overrides --time-zone option - -P Handful alias for --paging=never, overrides --paging option - -r, --raw-fields Disable unescaping and prettifying of field values - -V, --version Prints version information - -OPTIONS: - --buffer-size Buffer size [env: HL_BUFFER_SIZE=] [default: 2 MiB] - --color Color output options, one of { auto, always, never } [env: HL_COLOR=] [default: auto] - -C, --concurrency Number of processing threads [env: HL_CONCURRENCY=] - -f, --filter ... Filtering by field values in one of forms [=, ~=, ~~=, !=, !~=, !~~=] where ~ denotes substring match and ~~ denotes regular expression match - -h, --hide ... Hide fields with the specified keys - -e, --hide-empty-fields Hide empty fields, applies for null, string, object and array fields only [env: HL_HIDE_EMPTY_FIELDS=] - --interrupt-ignore-count Number of interrupts to ignore, i.e. Ctrl-C (SIGINT) [env: HL_INTERRUPT_IGNORE_COUNT=] [default: 3] - -l, --level Filtering by level, one of { d[ebug], i[nfo], w[arning], e[rror] } [env: HL_LEVEL=] - --max-message-size Maximum message size [env: HL_MAX_MESSAGE_SIZE=] [default: 64 MiB] - --paging Output paging options, one of { auto, always, never } [env: HL_PAGING=] [default: auto] - -H, --show ... Hide all fields except fields with the specified keys - -E, --show-empty-fields Show empty fields, overrides --hide-empty-fields option [env: HL_SHOW_EMPTY_FIELDS=] - --since Filtering by timestamp >= the value (--time-zone and --local options are honored) - --theme Color theme [env: HL_THEME=] [default: one-dark-green] - -t, --time-format Time format, see https://man7.org/linux/man-pages/man1/date.1.html [env: HL_TIME_FORMAT=] [default: %b %d %T.%3N] - -Z, --time-zone Time zone name, see column "TZ database name" at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones [env: HL_TIME_ZONE=] [default: UTC] - -u, --unhide ... Unhide fields with the specified keys - --until Filtering by timestamp <= the value (--time-zone and --local options are honored) + hl [OPTIONS] [--] [FILE]... ARGS: ... Files to process + +OPTIONS: + --buffer-size Buffer size [env: HL_BUFFER_SIZE=] [default: "2 MiB"] + -c Handful alias for --color=always, overrides --color option + -C, --concurrency Number of processing threads [env: HL_CONCURRENCY=] + --color Color output options [env: HL_COLOR=] [default: auto] [possible values: auto, always, never] + -e, --hide-empty-fields Hide empty fields, applies for null, string, object and array fields only [env: HL_HIDE_EMPTY_FIELDS=] + -E, --show-empty-fields Show empty fields, overrides --hide-empty-fields option [env: HL_SHOW_EMPTY_FIELDS=] + -f, --filter Filtering by field values in one of forms [=, ~=, ~~=, !=, !~=, !~~=] where ~ denotes substring match and ~~ denotes regular expression match + -h, --hide Hide fields with the specified keys + -H, --show Hide all fields except fields with the specified keys + --help Print help information + --interrupt-ignore-count Number of interrupts to ignore, i.e. Ctrl-C (SIGINT) [env: HL_INTERRUPT_IGNORE_COUNT=] [default: 3] + -l, --level Filtering by level [env: HL_LEVEL=] [possible values: error, warning, info, debug] + -L, --local Use local time zone, overrides --time-zone option + --list-themes List available themes and exit + --max-message-size Maximum message size [env: HL_MAX_MESSAGE_SIZE=] [default: "64 MiB"] + -P Handful alias for --paging=never, overrides --paging option + --paging Output paging options [env: HL_PAGING=] [default: auto] [possible values: auto, always, never] + -r, --raw-fields Disable unescaping and prettifying of field values + --since Filtering by timestamp >= the value (--time-zone and --local options are honored) + -t, --time-format Time format, see https://man7.org/linux/man-pages/man1/date.1.html [env: HL_TIME_FORMAT=] [default: "%y-%m-%d %T.%3N"] + --theme Color theme [env: HL_THEME=] [default: one-dark-green] + -u, --unhide Unhide fields with the specified keys + --until Filtering by timestamp <= the value (--time-zone and --local options are honored) + -V, --version Print version information + -Z, --time-zone Time zone name, see column "TZ database name" at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones [env: HL_TIME_ZONE=] [default: UTC] ``` ## Performance diff --git a/src/error.rs b/src/error.rs index 48d87e2a..84090b2e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,38 +13,21 @@ pub enum Error { #[error(transparent)] Io(#[from] io::Error), #[error(transparent)] - ParseIntError(#[from] ParseIntError), + SizeParseError(#[from] SizeParseError), #[error(transparent)] - TryFromIntError(#[from] TryFromIntError), + NonZeroSizeParseError(#[from] NonZeroSizeParseError), #[error("failed to load configuration: {0}")] Config(#[from] ConfigError), #[error(transparent)] Boxed(#[from] Box), #[error("file {filename:?} not found")] FileNotFoundError { filename: String }, - #[error("invalid level {value:?}, use any of {valid_values:?}")] - InvalidLevel { - value: String, - valid_values: Vec, - }, - #[error("invalid field kind {value:?}, use any of {valid_values:?}")] - InvalidFieldKind { - value: String, - valid_values: Vec, - }, - #[error( - "invalid size {0:?}, use {:?} or {:?} format for IEC units or {:?} format for SI units", - "64K", - "64KiB", - "64KB" - )] - InvalidSize(String), + #[error(transparent)] + InvalidLevel(#[from] InvalidLevelError), #[error("cannot recognize time {0:?}")] UnrecognizedTime(String), #[error("unknown theme {name:?}, use any of {known:?}")] UnknownTheme { name: String, known: Vec }, - #[error("zero size")] - ZeroSize, #[error("failed to parse utf-8 string: {0}")] Utf8Error(#[from] std::str::Utf8Error), #[error("failed to parse yaml: {0}")] @@ -55,5 +38,38 @@ pub enum Error { WrongRegularExpression(#[from] regex::Error), } +/// SizeParseError is an error which may occur when parsing size. +#[derive(Error, Debug)] +pub enum SizeParseError { + #[error(transparent)] + ParseIntError(#[from] ParseIntError), + #[error(transparent)] + TryFromIntError(#[from] TryFromIntError), + #[error( + "invalid size {0:?}, use {:?} or {:?} format for IEC units or {:?} format for SI units", + "64K", + "64KiB", + "64KB" + )] + InvalidSize(String), +} + +/// NonZeroSizeParseError is an error which may occur when parsing non-zero size. +#[derive(Error, Debug)] +pub enum NonZeroSizeParseError { + #[error(transparent)] + SizeParseError(#[from] SizeParseError), + #[error("zero size")] + ZeroSize, +} + +/// NonZeroSizeParseError is an error which may occur when parsing non-zero size. +#[derive(Error, Debug)] +#[error("invalid level {value:?}, use any of {valid_values:?}")] +pub struct InvalidLevelError { + pub value: String, + pub valid_values: Vec, +} + /// Result is an alias for standard result with bound Error type. pub type Result = std::result::Result; diff --git a/src/main.rs b/src/main.rs index 1c19ca9e..1c9b035c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,10 @@ use std::sync::Arc; use ansi_term::Colour; use chrono::{FixedOffset, Local, TimeZone}; use chrono_tz::{Tz, UTC}; +use clap::{ArgEnum, Parser}; use itertools::Itertools; use once_cell::sync::Lazy; use platform_dirs::AppDirs; -use structopt::{ - clap::{arg_enum, AppSettings::*}, - StructOpt, -}; // local imports use hl::datefmt::LinuxDateFormat; @@ -35,38 +32,40 @@ const APP_NAME: &str = "hl"; // --- /// JSON log converter to human readable representation. -#[derive(StructOpt)] -#[structopt(setting(ColorAuto), setting(ColoredHelp))] +#[derive(Parser)] +#[clap(version)] struct Opt { - /// Color output options, one of { auto, always, never }. - #[structopt( + /// Color output options. + #[clap( long, default_value = "auto", env = "HL_COLOR", overrides_with = "color" )] + #[clap(arg_enum)] color: ColorOption, // /// Handful alias for --color=always, overrides --color option. - #[structopt(short)] + #[clap(short)] color_always: bool, // - /// Output paging options, one of { auto, always, never }. - #[structopt( + /// Output paging options. + #[clap( long, default_value = "auto", env = "HL_PAGING", overrides_with = "paging" )] + #[clap(arg_enum)] paging: PagingOption, // /// Handful alias for --paging=never, overrides --paging option. - #[structopt(short = "P")] + #[clap(short = 'P')] paging_never: bool, // // /// Color theme. - #[structopt( + #[clap( long, default_value = &CONFIG.theme, env = "HL_THEME", @@ -75,11 +74,11 @@ struct Opt { theme: String, // /// Disable unescaping and prettifying of field values. - #[structopt(short, long)] + #[clap(short, long)] raw_fields: bool, // /// Number of interrupts to ignore, i.e. Ctrl-C (SIGINT). - #[structopt( + #[clap( long, default_value = "3", env = "HL_INTERRUPT_IGNORE_COUNT", @@ -88,52 +87,53 @@ struct Opt { interrupt_ignore_count: usize, // /// Buffer size. - #[structopt(long, default_value = "2 MiB", env="HL_BUFFER_SIZE", overrides_with = "buffer-size", parse(try_from_str = parse_non_zero_size))] + #[clap(long, default_value = "2 MiB", env="HL_BUFFER_SIZE", overrides_with = "buffer-size", parse(try_from_str = parse_non_zero_size))] buffer_size: usize, // /// Maximum message size. - #[structopt(long, default_value = "64 MiB", env="HL_MAX_MESSAGE_SIZE", overrides_with = "max-message-size", parse(try_from_str = parse_non_zero_size))] + #[clap(long, default_value = "64 MiB", env="HL_MAX_MESSAGE_SIZE", overrides_with = "max-message-size", parse(try_from_str = parse_non_zero_size))] max_message_size: usize, // /// Number of processing threads. - #[structopt( + #[clap( long, - short = "C", + short = 'C', env = "HL_CONCURRENCY", overrides_with = "concurrency" )] concurrency: Option, // /// Filtering by field values in one of forms [=, ~=, ~~=, !=, !~=, !~~=] where ~ denotes substring match and ~~ denotes regular expression match. - #[structopt(short, long, number_of_values = 1)] + #[clap(short, long, number_of_values = 1)] filter: Vec, // /// Hide fields with the specified keys. - #[structopt(long, short = "h", number_of_values = 1)] + #[clap(long, short = 'h', number_of_values = 1)] hide: Vec, // /// Hide all fields except fields with the specified keys. - #[structopt(long, short = "H", number_of_values = 1)] + #[structopt(long, short = 'H', number_of_values = 1)] show: Vec, // /// Unhide fields with the specified keys. - #[structopt(long, short = "u", number_of_values = 1)] + #[structopt(long, short = 'u', number_of_values = 1)] unhide: Vec, // - /// Filtering by level, one of { d[ebug], i[nfo], w[arning], e[rror] }. - #[structopt(short, long, env = "HL_LEVEL", overrides_with = "level")] + /// Filtering by level. + #[clap(short, long, env = "HL_LEVEL", overrides_with = "level")] + #[clap(arg_enum)] level: Option, // /// Filtering by timestamp >= the value (--time-zone and --local options are honored). - #[structopt(long, allow_hyphen_values = true)] + #[clap(long, allow_hyphen_values = true)] since: Option, // /// Filtering by timestamp <= the value (--time-zone and --local options are honored). - #[structopt(long, allow_hyphen_values = true)] + #[clap(long, allow_hyphen_values = true)] until: Option, // /// Time format, see https://man7.org/linux/man-pages/man1/date.1.html. - #[structopt( + #[clap( short, long, env="HL_TIME_FORMAT", @@ -143,46 +143,42 @@ struct Opt { time_format: String, // /// Time zone name, see column "TZ database name" at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. - #[structopt(long, short = "Z", env="HL_TIME_ZONE", default_value = &CONFIG.time_zone.name(), overrides_with = "time-zone")] + #[clap(long, short = 'Z', env="HL_TIME_ZONE", default_value = &CONFIG.time_zone.name(), overrides_with = "time-zone")] time_zone: Tz, // /// Use local time zone, overrides --time-zone option. - #[structopt(long, short = "L")] + #[clap(long, short = 'L')] local: bool, // /// Files to process - #[structopt(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] files: Vec, // /// Hide empty fields, applies for null, string, object and array fields only. - #[structopt(long, short = "e", env = "HL_HIDE_EMPTY_FIELDS")] + #[clap(long, short = 'e', env = "HL_HIDE_EMPTY_FIELDS")] hide_empty_fields: bool, // /// Show empty fields, overrides --hide-empty-fields option. - #[structopt(long, short = "E", env = "HL_SHOW_EMPTY_FIELDS")] + #[clap(long, short = 'E', env = "HL_SHOW_EMPTY_FIELDS")] show_empty_fields: bool, // /// List available themes and exit. - #[structopt(long)] + #[clap(long)] list_themes: bool, } -arg_enum! { - #[derive(Debug)] - enum ColorOption { - Auto, - Always, - Never, - } +#[derive(ArgEnum, Debug, Clone, Copy)] +enum ColorOption { + Auto, + Always, + Never, } -arg_enum! { - #[derive(Debug)] - enum PagingOption { - Auto, - Always, - Never, - } +#[derive(ArgEnum, Debug, Clone, Copy)] +enum PagingOption { + Auto, + Always, + Never, } // --- @@ -196,22 +192,22 @@ fn load_config() -> Settings { Settings::load(&app_dirs).unwrap() } -fn parse_size(s: &str) -> Result { +fn parse_size(s: &str) -> std::result::Result { match bytefmt::parse(s) { Ok(value) => Ok(usize::try_from(value)?), Err(_) => { if let Ok(value) = bytefmt::parse(s.to_owned() + "ib") { return Ok(usize::try_from(value)?); } - Err(Error::InvalidSize(s.into())) + Err(SizeParseError::InvalidSize(s.into())) } } } -fn parse_non_zero_size(s: &str) -> Result { +fn parse_non_zero_size(s: &str) -> std::result::Result { let value = parse_size(s)?; if value == 0 { - Err(Error::ZeroSize) + Err(NonZeroSizeParseError::ZeroSize) } else { Ok(value) } @@ -222,7 +218,7 @@ fn parse_non_zero_size(s: &str) -> Result { fn run() -> Result<()> { let app_dirs = AppDirs::new(Some("hl"), true).unwrap(); let settings = Settings::load(&app_dirs)?; - let opt = Opt::from_args(); + let opt = Opt::parse(); let stdout_is_atty = || atty::is(atty::Stream::Stdout); let color_supported = if stdout_is_atty() { if let Err(err) = hl::enable_ansi_support() { diff --git a/src/types.rs b/src/types.rs index 75d63cd0..1bf3710f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,17 +1,19 @@ // std imports use std::cmp::Ord; +use std::result::Result; use std::str::FromStr; // third-party imports +use clap::ArgEnum; use enum_map::Enum; use serde::Deserialize; // local imports -use crate::error::{Error, Result}; +use crate::error::InvalidLevelError; // --- -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Enum)] +#[derive(ArgEnum, Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Enum)] #[serde(rename_all = "kebab-case")] pub enum Level { Error, @@ -21,9 +23,9 @@ pub enum Level { } impl FromStr for Level { - type Err = Error; + type Err = InvalidLevelError; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { let matches = |value| s.eq_ignore_ascii_case(value); if matches("e") || matches("error") { Ok(Level::Error) @@ -34,7 +36,7 @@ impl FromStr for Level { } else if matches("d") || matches("debug") { Ok(Level::Debug) } else { - Err(Error::InvalidLevel { + Err(InvalidLevelError { value: s.into(), valid_values: vec![ "error".into(), @@ -50,7 +52,6 @@ impl FromStr for Level { // --- #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[serde(rename_all = "kebab-case")] pub enum FieldKind { Time, Level, From 17f7e63adfba00e589792fa26d4736350143f084 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Thu, 3 Feb 2022 01:11:54 +0300 Subject: [PATCH 5/6] new: use non zero usize type for buffer size and max message size --- src/app.rs | 11 ++++++----- src/main.rs | 14 +++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5e03097b..d38860e6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -8,6 +8,7 @@ use crossbeam_channel::RecvError; use crossbeam_utils::thread; use itertools::izip; use serde_json as json; +use std::num::NonZeroUsize; use crate::datefmt::{DateTimeFormat, DateTimeFormatter}; use crate::error::*; @@ -23,8 +24,8 @@ pub struct Options { pub theme: Arc, pub time_format: DateTimeFormat, pub raw_fields: bool, - pub buffer_size: usize, - pub max_message_size: usize, + pub buffer_size: NonZeroUsize, + pub max_message_size: NonZeroUsize, pub concurrency: usize, pub filter: Filter, pub fields: FieldOptions, @@ -52,8 +53,8 @@ impl App { output: &mut (dyn Write + Send + Sync), ) -> Result<()> { let n = self.options.concurrency; - let sfi = Arc::new(SegmentBufFactory::new(self.options.buffer_size)); - let bfo = BufFactory::new(self.options.buffer_size); + let sfi = Arc::new(SegmentBufFactory::new(self.options.buffer_size.into())); + let bfo = BufFactory::new(self.options.buffer_size.into()); let parser = Parser::new(ParserSettings::new( &self.options.fields.settings, self.options.filter.since.is_some() || self.options.filter.until.is_some(), @@ -70,7 +71,7 @@ impl App { let reader = scope.spawn(closure!(clone sfi, |_| -> Result<()> { let mut sn: usize = 0; let scanner = Scanner::new(sfi, "\n".to_string()); - for item in scanner.items(input).with_max_segment_size(self.options.max_message_size) { + for item in scanner.items(input).with_max_segment_size(self.options.max_message_size.into()) { if let Err(_) = txi[sn % n].send(item?) { break; } diff --git a/src/main.rs b/src/main.rs index 1c9b035c..487f2ab3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use clap::{ArgEnum, Parser}; use itertools::Itertools; use once_cell::sync::Lazy; use platform_dirs::AppDirs; +use std::num::NonZeroUsize; // local imports use hl::datefmt::LinuxDateFormat; @@ -88,11 +89,11 @@ struct Opt { // /// Buffer size. #[clap(long, default_value = "2 MiB", env="HL_BUFFER_SIZE", overrides_with = "buffer-size", parse(try_from_str = parse_non_zero_size))] - buffer_size: usize, + buffer_size: NonZeroUsize, // /// Maximum message size. #[clap(long, default_value = "64 MiB", env="HL_MAX_MESSAGE_SIZE", overrides_with = "max-message-size", parse(try_from_str = parse_non_zero_size))] - max_message_size: usize, + max_message_size: NonZeroUsize, // /// Number of processing threads. #[clap( @@ -204,12 +205,11 @@ fn parse_size(s: &str) -> std::result::Result { } } -fn parse_non_zero_size(s: &str) -> std::result::Result { - let value = parse_size(s)?; - if value == 0 { - Err(NonZeroSizeParseError::ZeroSize) +fn parse_non_zero_size(s: &str) -> std::result::Result { + if let Some(value) = NonZeroUsize::new(parse_size(s)?) { + Ok(NonZeroUsize::from(value)) } else { - Ok(value) + Err(NonZeroSizeParseError::ZeroSize) } } From 4315f8619d02e6c230cd32ae79c40027ea373aae Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Tue, 7 Jun 2022 22:02:52 +0200 Subject: [PATCH 6/6] new: change version to 0.11.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b7d2f5e..47d9070c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -765,7 +765,7 @@ dependencies = [ [[package]] name = "hl" -version = "0.11.2-alpha.0" +version = "0.11.2" dependencies = [ "ansi_term", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index a86534a9..20be67ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ categories = ["command-line-utilities"] description = "Utility for viewing json-formatted log files." keywords = ["cli", "human", "log"] name = "hl" -version = "0.11.2-alpha.0" +version = "0.11.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html