fix(zebrad): accept default subcommand arguments and print consistent usage information for top-level 'help' subcommand (#6801)

* updates Cargo.toml

* Migrate to abscissa 0.7.0

* Avoid panic from calling color_eyre::install twice

* Uses 'start' as the default subcommand

* updates default cmd logic

* Fixes minor cli issues

* removes outdated check in acceptance test

* Adds a test for process_cli_args, fixes version_args test.

Adds -V to process_cli_args match case

* Revert "fix(clippy): Silence future-incompat warnings until we upgrade Abscissa (#6024)"

This reverts commit dd90f79b48.

* Drops the worker guard to flush logs when zebra shuts down

* Adds cargo feature to clap

* restores process_cli_args

* updates deny.toml

* Updates EntryPoint help template

* Updates subcommand help msgs

* removes trailing whitespace, capitalizes sentences

* Apply suggestions from code review

Co-authored-by: teor <teor@riseup.net>

* revert parts of revert "Revert fix(clippy): Silence future-incompat warnings until we upgrade Abscissa"

* Applies suggestions from code review

* Moves EntryPoint to its own module

* fixes version_args test

* Updates changelog

* Prunes redundant test cases

* Apply suggestions from code review

Co-authored-by: teor <teor@riseup.net>

* Revert "Prunes redundant test cases"

This reverts commit 3f73979184.

* Update zebrad/src/commands/entry_point.rs

Co-authored-by: teor <teor@riseup.net>

* Add missing import

* Updates `process_cli_args` to return a result

---------

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Arya 2023-06-07 02:03:42 -04:00 committed by GitHub
parent 428493e3de
commit 59086c7d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 476 additions and 556 deletions

View File

@ -1,11 +1,5 @@
# Zebra cargo configuration
# Disabled until we upgrade to abscissa 0.7 or later:
# https://github.com/ZcashFoundation/zebra/issues/5502
# https://doc.rust-lang.org/cargo/reference/future-incompat-report.html
[future-incompat-report]
frequency = "never"
# Flags that apply to all Zebra crates and configurations
[target.'cfg(all())']
rustflags = [

View File

@ -5,6 +5,18 @@ All notable changes to Zebra are 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).
## [Zebra 1.0.0-rc.9](https://github.com/ZcashFoundation/zebra/releases/tag/v1.0.0-rc.9) - XXXX-XX-XX
In this release ...
### Breaking Changes
- The version subcommand has been replaced with a --version/-V flag ([#6801](https://github.com/ZcashFoundation/zebra/pull/6801))
- Zebra now accepts filters for the start command when no subcommand is provided ([#6801](https://github.com/ZcashFoundation/zebra/pull/6801))
...
## [Zebra 1.0.0-rc.8](https://github.com/ZcashFoundation/zebra/releases/tag/v1.0.0-rc.8) - 2023-05-10
Starting in this release, Zebra has implemented an "end of support" halt. Just like `zcashd`, the `zebrad` binary will stop running 16 weeks after the last release date.

View File

@ -4,39 +4,36 @@ version = 3
[[package]]
name = "abscissa_core"
version = "0.5.2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a07677093120a02583717b6dd1ef81d8de1e8d01bd226c83f0f9bdf3e56bb3a"
checksum = "8346a52bf3fb445d5949d144c37360ad2f1d7950cfcc6d4e9e4999b1cd1bd42a"
dependencies = [
"abscissa_derive",
"arc-swap",
"backtrace",
"canonical-path",
"chrono",
"color-backtrace",
"generational-arena",
"gumdrop",
"libc",
"clap 4.3.0",
"color-eyre",
"fs-err",
"once_cell",
"regex",
"secrecy",
"semver 0.9.0",
"semver 1.0.17",
"serde",
"signal-hook",
"termcolor",
"toml 0.5.11",
"tracing",
"tracing-log",
"tracing-subscriber 0.1.6",
"tracing-subscriber",
"wait-timeout",
]
[[package]]
name = "abscissa_derive"
version = "0.5.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74f5722bc48763cb9d81d8427ca05b6aa2842f6632cf8e4c0a29eef9baececcc"
checksum = "55bfb86e57d13c06e482c570826ddcddcc8f07fab916760e8911141d4fda8b62"
dependencies = [
"darling 0.10.2",
"ident_case",
"proc-macro2 1.0.56",
"quote 1.0.27",
@ -142,15 +139,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@ -160,18 +148,67 @@ dependencies = [
"winapi",
]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "anstyle-parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "arc-swap"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
name = "arrayref"
version = "0.3.7"
@ -659,11 +696,8 @@ checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"time 0.1.45",
"wasm-bindgen",
"winapi",
]
@ -722,7 +756,7 @@ version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term 0.12.1",
"ansi_term",
"atty",
"bitflags 1.3.2",
"strsim 0.8.0",
@ -738,6 +772,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
@ -746,9 +782,24 @@ version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990"
dependencies = [
"anstream",
"anstyle",
"bitflags 1.3.2",
"clap_lex",
"once_cell",
"strsim 0.10.0",
]
[[package]]
name = "clap_derive"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b"
dependencies = [
"heck 0.4.1",
"proc-macro2 1.0.56",
"quote 1.0.27",
"syn 2.0.15",
]
[[package]]
@ -767,17 +818,6 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "color-backtrace"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65d13f1078cc63c791d0deba0dd43db37c9ec02b311f10bed10b577016f3a957"
dependencies = [
"atty",
"backtrace",
"termcolor",
]
[[package]]
name = "color-eyre"
version = "0.6.2"
@ -806,6 +846,12 @@ dependencies = [
"tracing-error",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "console"
version = "0.15.5"
@ -852,7 +898,7 @@ dependencies = [
"tonic",
"tracing",
"tracing-core",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -1074,16 +1120,6 @@ dependencies = [
"syn 2.0.15",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core 0.10.2",
"darling_macro 0.10.2",
]
[[package]]
name = "darling"
version = "0.13.4"
@ -1104,20 +1140,6 @@ dependencies = [
"darling_macro 0.20.1",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2 1.0.56",
"quote 1.0.27",
"strsim 0.9.3",
"syn 1.0.109",
]
[[package]]
name = "darling_core"
version = "0.13.4"
@ -1146,17 +1168,6 @@ dependencies = [
"syn 2.0.15",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core 0.10.2",
"quote 1.0.27",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
@ -1483,6 +1494,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "fs-err"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
[[package]]
name = "funty"
version = "2.0.0"
@ -1578,15 +1595,6 @@ dependencies = [
"slab",
]
[[package]]
name = "generational-arena"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601"
dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@ -1671,26 +1679,6 @@ dependencies = [
"subtle",
]
[[package]]
name = "gumdrop"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde"
dependencies = [
"gumdrop_derive",
]
[[package]]
name = "gumdrop_derive"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7"
dependencies = [
"proc-macro2 1.0.56",
"quote 1.0.27",
"syn 1.0.109",
]
[[package]]
name = "h2"
version = "0.3.18"
@ -2422,15 +2410,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matchers"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
dependencies = [
"regex-automata",
]
[[package]]
name = "matchers"
version = "0.1.0"
@ -2456,12 +2435,6 @@ dependencies = [
"rayon",
]
[[package]]
name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]]
name = "memchr"
version = "2.5.0"
@ -2882,15 +2855,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owning_ref"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "owo-colors"
version = "3.5.0"
@ -2973,7 +2937,7 @@ dependencies = [
"instant",
"libc",
"redox_syscall 0.2.16",
"smallvec 1.10.0",
"smallvec",
"winapi",
]
@ -2986,7 +2950,7 @@ dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall 0.2.16",
"smallvec 1.10.0",
"smallvec",
"windows-sys 0.45.0",
]
@ -3939,9 +3903,9 @@ dependencies = [
[[package]]
name = "secrecy"
version = "0.6.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9182278ed645df3477a9c27bfee0621c621aa16f6972635f7f795dae3d81070f"
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
dependencies = [
"serde",
"zeroize",
@ -3977,7 +3941,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
"serde",
]
[[package]]
@ -3985,6 +3948,9 @@ name = "semver"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
dependencies = [
"serde",
]
[[package]]
name = "semver-parser"
@ -4058,7 +4024,7 @@ dependencies = [
"sentry-backtrace",
"sentry-core",
"tracing-core",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -4073,7 +4039,7 @@ dependencies = [
"serde",
"serde_json",
"thiserror",
"time 0.3.21",
"time",
"url",
"uuid",
]
@ -4163,7 +4129,7 @@ dependencies = [
"serde",
"serde_json",
"serde_with_macros 3.0.0",
"time 0.3.21",
"time",
]
[[package]]
@ -4229,16 +4195,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "signal-hook"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@ -4269,15 +4225,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0"
dependencies = [
"maybe-uninit",
]
[[package]]
name = "smallvec"
version = "1.10.0"
@ -4331,12 +4278,6 @@ dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
@ -4355,12 +4296,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "strsim"
version = "0.10.0"
@ -4515,17 +4450,6 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "time"
version = "0.3.21"
@ -4879,8 +4803,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
dependencies = [
"crossbeam-channel",
"time 0.3.21",
"tracing-subscriber 0.3.17",
"time",
"tracing-subscriber",
]
[[package]]
@ -4911,7 +4835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
dependencies = [
"tracing",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -4922,7 +4846,7 @@ checksum = "0bae117ee14789185e129aaee5d93750abe67fdc5a9a62650452bfe4e122a3a9"
dependencies = [
"lazy_static",
"tracing",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -4943,7 +4867,7 @@ checksum = "ba316a74e8fc3c3896a850dba2375928a9fa171b085ecddfc7c054d39970f3fd"
dependencies = [
"libc",
"tracing-core",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -4957,35 +4881,18 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "192ca16595cdd0661ce319e8eede9c975f227cdaabc4faaefdc256f43d852e45"
dependencies = [
"ansi_term 0.11.0",
"chrono",
"lazy_static",
"matchers 0.0.1",
"owning_ref",
"regex",
"smallvec 0.6.14",
"tracing-core",
"tracing-log",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
dependencies = [
"matchers 0.1.0",
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec 1.10.0",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
@ -5000,7 +4907,7 @@ checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4"
dependencies = [
"lazy_static",
"tracing-core",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
"tracing-test-macro",
]
@ -5157,6 +5064,12 @@ dependencies = [
"serde",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.3.2"
@ -5195,7 +5108,7 @@ dependencies = [
"git2",
"rustc_version 0.4.0",
"rustversion",
"time 0.3.21",
"time",
]
[[package]]
@ -5245,12 +5158,6 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -5830,7 +5737,7 @@ dependencies = [
"tracing",
"tracing-error",
"tracing-futures",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
"zcash_proofs",
"zebra-chain",
"zebra-node-services",
@ -6001,7 +5908,7 @@ dependencies = [
"tower",
"tracing",
"tracing-error",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
]
[[package]]
@ -6019,7 +5926,7 @@ dependencies = [
"tinyvec",
"tokio",
"tracing-error",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
"zebra-chain",
"zebra-node-services",
"zebra-rpc",
@ -6032,11 +5939,11 @@ dependencies = [
"abscissa_core",
"atty",
"chrono",
"clap 4.3.0",
"color-eyre",
"console-subscriber",
"dirs",
"futures",
"gumdrop",
"hex",
"howudoin",
"humantime-serde",
@ -6077,7 +5984,7 @@ dependencies = [
"tracing-flame",
"tracing-futures",
"tracing-journald",
"tracing-subscriber 0.3.17",
"tracing-subscriber",
"tracing-test",
"vergen",
"zebra-chain",

View File

@ -90,9 +90,10 @@ skip-tree = [
# Optional dependencies
# upgrade abscissa (required dependency) and arti (optional dependency)
{ name = "darling", version = "=0.10.2" },
{ name = "semver", version = "=0.9.0" },
{ name = "tracing-subscriber", version = "=0.1.6" },
# wait for packed_simd_2 to upgrade
{ name = "libm", version = "=0.1.4" },
# Elasticsearch dependencies

View File

@ -115,8 +115,8 @@ zebra-node-services = { path = "../zebra-node-services" }
zebra-rpc = { path = "../zebra-rpc" }
zebra-state = { path = "../zebra-state" }
abscissa_core = "0.5"
gumdrop = { version = "0.7", features = ["default_expr"]}
abscissa_core = "0.7.0"
clap = { version = "4.3.0", features = ["cargo"] }
chrono = { version = "0.4.26", default-features = false, features = ["clock", "std"] }
humantime-serde = "1.1.1"
indexmap = "1.9.3"
@ -191,7 +191,7 @@ vergen = { version = "8.2.1", default-features = false, features = ["cargo", "gi
tonic-build = { version = "0.9.2", optional = true }
[dev-dependencies]
abscissa_core = { version = "0.5", features = ["testing"] }
abscissa_core = { version = "0.7.0", features = ["testing"] }
hex = "0.4.3"
jsonrpc-core = "18.0.0"
once_cell = "1.18.0"

View File

@ -1,27 +1,24 @@
//! Zebrad Abscissa Application
use std::{fmt::Write as _, io::Write as _, process};
use std::{env, fmt::Write as _, io::Write as _, process, sync::Arc};
use abscissa_core::{
application::{self, AppCell},
config::{self, Configurable},
config::CfgCell,
status_err,
terminal::{component::Terminal, stderr, stdout, ColorChoice},
Application, Component, FrameworkError, Shutdown, StandardPaths, Version,
Application, Component, Configurable, FrameworkError, Shutdown, StandardPaths, Version,
};
use zebra_network::constants::PORT_IN_USE_ERROR;
use zebra_state::constants::{DATABASE_FORMAT_VERSION, LOCK_FILE_ERROR};
use crate::{
commands::ZebradCmd,
commands::EntryPoint,
components::{sync::end_of_support::EOS_PANIC_MESSAGE_HEADER, tracing::Tracing},
config::ZebradConfig,
};
mod entry_point;
use entry_point::EntryPoint;
/// See <https://docs.rs/abscissa_core/latest/src/abscissa_core/application/exit.rs.html#7-10>
/// Print a fatal error message and exit
fn fatal_error(app_name: String, err: &dyn std::error::Error) -> ! {
@ -32,25 +29,6 @@ fn fatal_error(app_name: String, err: &dyn std::error::Error) -> ! {
/// Application state
pub static APPLICATION: AppCell<ZebradApp> = AppCell::new();
/// Obtain a read-only (multi-reader) lock on the application state.
///
/// Panics if the application state has not been initialized.
pub fn app_reader() -> application::lock::Reader<ZebradApp> {
APPLICATION.read()
}
/// Obtain an exclusive mutable lock on the application state.
pub fn app_writer() -> application::lock::Writer<ZebradApp> {
APPLICATION.write()
}
/// Obtain a read-only (multi-reader) lock on the application configuration.
///
/// Panics if the application configuration has not been loaded.
pub fn app_config() -> config::Reader<ZebradApp> {
config::Reader::new(&APPLICATION)
}
/// Returns the zebrad version for this build, in SemVer 2.0 format.
///
/// Includes the git commit and the number of commits since the last version
@ -117,10 +95,10 @@ pub fn user_agent() -> String {
}
/// Zebrad Application
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct ZebradApp {
/// Application configuration.
config: Option<ZebradConfig>,
config: CfgCell<ZebradConfig>,
/// Application state.
state: application::State<Self>,
@ -147,21 +125,6 @@ impl ZebradApp {
}
}
/// Initialize a new application instance.
///
/// By default no configuration is loaded, and the framework state is
/// initialized to a default, empty state (no components, threads, etc).
#[allow(unknown_lints)]
#[allow(clippy::derivable_impls)]
impl Default for ZebradApp {
fn default() -> Self {
Self {
config: None,
state: application::State::default(),
}
}
}
impl Application for ZebradApp {
/// Entrypoint command for this application.
type Cmd = EntryPoint;
@ -173,8 +136,8 @@ impl Application for ZebradApp {
type Paths = StandardPaths;
/// Accessor for application configuration.
fn config(&self) -> &ZebradConfig {
self.config.as_ref().expect("config not loaded")
fn config(&self) -> Arc<ZebradConfig> {
self.config.read()
}
/// Borrow the application state immutably.
@ -182,34 +145,22 @@ impl Application for ZebradApp {
&self.state
}
/// Borrow the application state mutably.
fn state_mut(&mut self) -> &mut application::State<Self> {
&mut self.state
}
/// Returns the framework components used by this application.
fn framework_components(
&mut self,
command: &Self::Cmd,
_command: &Self::Cmd,
) -> Result<Vec<Box<dyn Component<Self>>>, FrameworkError> {
// Automatically use color if we're outputting to a terminal
// TODO: Open a PR in abscissa to add a TerminalBuilder for opting out
// of the `color_eyre::install` part of `Terminal::new` without
// ColorChoice::Never?
// The Tracing component uses stdout directly and will apply colors
// `if Self::outputs_are_ttys() && config.tracing.use_colors`
//
// The `abcissa` docs claim that abscissa implements `Auto`, but it
// does not - except in `color_backtrace` backtraces.
let mut term_colors = self.term_colors(command);
if term_colors == ColorChoice::Auto {
// We want to disable colors on a per-stream basis, but that feature
// can only be implemented inside the terminal component streams.
// Instead, if either output stream is not a terminal, disable
// colors.
//
// We'd also like to check `config.tracing.use_color` here, but the
// config has not been loaded yet.
if !Self::outputs_are_ttys() {
term_colors = ColorChoice::Never;
}
}
let terminal = Terminal::new(term_colors);
// Note: It's important to use `ColorChoice::Never` here to avoid panicking in
// `register_components()` below if `color_eyre::install()` is called
// after `color_spantrace` has been initialized.
let terminal = Terminal::new(ColorChoice::Never);
Ok(vec![Box::new(terminal)])
}
@ -394,23 +345,9 @@ impl Application for ZebradApp {
.build_global()
.expect("unable to initialize rayon thread pool");
self.config = Some(config);
let cfg_ref = self
.config
.as_ref()
.expect("config is loaded before register_components");
let default_filter = command
.command
.as_ref()
.map(|zcmd| zcmd.default_tracing_filter(command.verbose, command.help))
.unwrap_or("warn");
let is_server = command
.command
.as_ref()
.map(ZebradCmd::is_server)
.unwrap_or(false);
let cfg_ref = &config;
let default_filter = command.cmd().default_tracing_filter(command.verbose);
let is_server = command.cmd().is_server();
// Ignore the configured tracing filter for short-lived utility commands
let mut tracing_config = cfg_ref.tracing.clone();
@ -436,7 +373,7 @@ impl Application for ZebradApp {
// Activate the global span, so it's visible when we load the other
// components. Space is at a premium here, so we use an empty message,
// short commit hash, and the unique part of the network name.
let net = &self.config.clone().unwrap().network.network.to_string()[..4];
let net = &config.network.network.to_string()[..4];
let global_span = if let Some(git_commit) = ZebradApp::git_commit() {
error_span!("", zebrad = git_commit, net)
} else {
@ -459,7 +396,10 @@ impl Application for ZebradApp {
components.push(Box::new(MetricsEndpoint::new(&metrics_config)?));
}
self.state.components.register(components)
self.state.components_mut().register(components)?;
// Fire callback to signal state in the application lifecycle
self.after_config(config)
}
/// Load this application's configuration and initialize its components.
@ -468,16 +408,7 @@ impl Application for ZebradApp {
// Create and register components with the application.
// We do this first to calculate a proper dependency ordering before
// application configuration is processed
self.register_components(command)?;
// Fire callback to signal state in the application lifecycle
let config = self
.config
.take()
.expect("register_components always populates the config");
self.after_config(config)?;
Ok(())
self.register_components(command)
}
/// Post-configuration lifecycle callback.
@ -487,13 +418,13 @@ impl Application for ZebradApp {
/// possible.
fn after_config(&mut self, config: Self::Cfg) -> Result<(), FrameworkError> {
// Configure components
self.state.components.after_config(&config)?;
self.config = Some(config);
self.state.components_mut().after_config(&config)?;
self.config.set_once(config);
Ok(())
}
fn shutdown(&mut self, shutdown: Shutdown) -> ! {
fn shutdown(&self, shutdown: Shutdown) -> ! {
// Some OSes require a flush to send all output to the terminal.
// zebrad's logging uses Abscissa, so we flush its streams.
//
@ -503,25 +434,33 @@ impl Application for ZebradApp {
let _ = stdout().lock().flush();
let _ = stderr().lock().flush();
if let Err(e) = self.state().components.shutdown(self, shutdown) {
let app_name = self.name().to_string();
let shutdown_result = self.state().components().shutdown(self, shutdown);
// Swap out a fake app so we can trigger the destructor on the original
let _ = std::mem::take(self);
self.state()
.components_mut()
.get_downcast_mut::<Tracing>()
.map(Tracing::shutdown);
if let Err(e) = shutdown_result {
let app_name = self.name().to_string();
fatal_error(app_name, &e);
}
// Swap out a fake app so we can trigger the destructor on the original
let _ = std::mem::take(self);
match shutdown {
Shutdown::Graceful => process::exit(0),
Shutdown::Forced => process::exit(1),
Shutdown::Crash => process::exit(2),
}
}
}
fn version(&self) -> Version {
app_version()
}
/// Boot the given application, parsing subcommand and options from
/// command-line arguments, and terminating when complete.
// <https://docs.rs/abscissa_core/0.7.0/src/abscissa_core/application.rs.html#174-178>
pub fn boot(app_cell: &'static AppCell<ZebradApp>) -> ! {
let args =
EntryPoint::process_cli_args(env::args_os().collect()).unwrap_or_else(|err| err.exit());
ZebradApp::run(app_cell, args);
process::exit(0);
}

View File

@ -1,111 +0,0 @@
//! Zebrad EntryPoint
use crate::{
commands::{StartCmd, ZebradCmd},
config::ZebradConfig,
};
use std::path::PathBuf;
use abscissa_core::{
command::{Command, Usage},
config::Configurable,
FrameworkError, Options, Runnable,
};
// (See https://docs.rs/abscissa_core/0.5.2/src/abscissa_core/command/entrypoint.rs.html)
/// Toplevel entrypoint command.
///
/// Handles obtaining toplevel help as well as verbosity settings.
#[derive(Debug, Options)]
pub struct EntryPoint {
/// Path to the configuration file
#[options(short = "c", help = "path to configuration file")]
pub config: Option<PathBuf>,
/// Obtain help about the current command
#[options(short = "h", help = "print help message")]
pub help: bool,
/// Increase verbosity setting
#[options(short = "v", help = "be verbose")]
pub verbose: bool,
/// Subcommand to execute.
///
/// The `command` option will delegate option parsing to the command type,
/// starting at the first free argument. Defaults to start.
#[options(command, default_expr = "Some(ZebradCmd::Start(StartCmd::default()))")]
pub command: Option<ZebradCmd>,
}
impl EntryPoint {
/// Borrow the underlying command type
fn command(&self) -> &ZebradCmd {
if self.help {
let _ = Usage::for_command::<EntryPoint>().print_info();
let _ = Usage::for_command::<EntryPoint>().print_usage();
let _ = Usage::for_command::<ZebradCmd>().print_usage();
std::process::exit(0);
}
self.command
.as_ref()
.expect("Some(ZebradCmd::Start(StartCmd::default()) as default value")
}
}
impl Runnable for EntryPoint {
fn run(&self) {
self.command().run()
}
}
impl Command for EntryPoint {
/// Name of this program as a string
fn name() -> &'static str {
ZebradCmd::name()
}
/// Description of this program
fn description() -> &'static str {
ZebradCmd::description()
}
/// Version of this program
fn version() -> &'static str {
ZebradCmd::version()
}
/// Authors of this program
fn authors() -> &'static str {
ZebradCmd::authors()
}
/// Get usage information for a particular subcommand (if available)
fn subcommand_usage(command: &str) -> Option<Usage> {
ZebradCmd::subcommand_usage(command)
}
}
impl Configurable<ZebradConfig> for EntryPoint {
/// Path to the command's configuration file
fn config_path(&self) -> Option<PathBuf> {
match &self.config {
// Use explicit `-c`/`--config` argument if passed
Some(cfg) => Some(cfg.clone()),
// Otherwise defer to the toplevel command's config path logic
None => self.command.as_ref().and_then(|cmd| cmd.config_path()),
}
}
/// Process the configuration after it has been loaded, potentially
/// modifying it or returning an error if options are incompatible
fn process_config(&self, config: ZebradConfig) -> Result<ZebradConfig, FrameworkError> {
match &self.command {
Some(cmd) => cmd.process_config(config),
None => Ok(config),
}
}
}

View File

@ -1,8 +1,8 @@
//! Main entry point for Zebrad
use zebrad::application::APPLICATION;
use zebrad::application::{boot, APPLICATION};
/// Process entry point for `zebrad`
fn main() {
abscissa_core::boot(&APPLICATION);
boot(&APPLICATION);
}

View File

@ -2,62 +2,49 @@
mod copy_state;
mod download;
mod entry_point;
mod generate;
mod start;
mod tip_height;
mod version;
#[cfg(test)]
mod tests;
use self::ZebradCmd::*;
use self::{
copy_state::CopyStateCmd, download::DownloadCmd, generate::GenerateCmd,
tip_height::TipHeightCmd, version::VersionCmd,
tip_height::TipHeightCmd,
};
pub use self::start::StartCmd;
pub use self::{entry_point::EntryPoint, start::StartCmd};
use crate::config::ZebradConfig;
use abscissa_core::{
config::Override, Command, Configurable, FrameworkError, Help, Options, Runnable,
};
use abscissa_core::{config::Override, Command, Configurable, FrameworkError, Runnable};
use std::path::PathBuf;
/// Zebrad Configuration Filename
pub const CONFIG_FILE: &str = "zebrad.toml";
/// Zebrad Subcommands
#[derive(Command, Debug, Options)]
#[derive(Command, Debug, clap::Subcommand)]
pub enum ZebradCmd {
/// The `copy-state` subcommand, used to debug cached chain state
/// The `copy-state` subcommand, used to debug cached chain state (expert users only)
// TODO: hide this command from users in release builds (#3279)
#[options(help = "copy cached chain state (debug only)")]
CopyState(CopyStateCmd),
/// The `download` subcommand
#[options(help = "pre-download required parameter files")]
// The `download` subcommand
/// Pre-download required Zcash Sprout and Sapling parameter files
Download(DownloadCmd),
/// The `generate` subcommand
#[options(help = "generate a skeleton configuration")]
/// Generate a default `zebrad.toml` configuration
Generate(GenerateCmd),
/// The `help` subcommand
#[options(help = "get usage information, \
use help <subcommand> for subcommand usage information, \
or --help flag to see top-level options")]
Help(Help<Self>),
/// The `start` subcommand
#[options(help = "start the application")]
/// Start the application (default command)
Start(StartCmd),
/// The `tip-height` subcommand
#[options(help = "get the block height of Zebra's persisted chain state")]
/// Print the tip block height of Zebra's chain state on disk
TipHeight(TipHeightCmd),
/// The `version` subcommand
#[options(help = "display version information")]
Version(VersionCmd),
}
impl ZebradCmd {
@ -73,27 +60,26 @@ impl ZebradCmd {
CopyState(_) | Start(_) => true,
// Utility commands that don't use server components
Download(_) | Generate(_) | Help(_) | TipHeight(_) | Version(_) => false,
Download(_) | Generate(_) | TipHeight(_) => false,
}
}
/// Returns the default log level for this command, based on the `verbose` command line flag.
///
/// Some commands need to be quiet by default.
pub(crate) fn default_tracing_filter(&self, verbose: bool, help: bool) -> &'static str {
pub(crate) fn default_tracing_filter(&self, verbose: bool) -> &'static str {
let only_show_warnings = match self {
// Commands that generate quiet output by default.
// This output:
// - is used by automated tools, or
// - needs to be read easily.
Generate(_) | TipHeight(_) | Help(_) | Version(_) => true,
Generate(_) | TipHeight(_) => true,
// Commands that generate informative logging output by default.
CopyState(_) | Download(_) | Start(_) => false,
};
// set to warn so that usage info is printed without info-level logs from component registration
if help || (only_show_warnings && !verbose) {
if only_show_warnings && !verbose {
"warn"
} else if only_show_warnings || !verbose {
"info"
@ -109,10 +95,8 @@ impl Runnable for ZebradCmd {
CopyState(cmd) => cmd.run(),
Download(cmd) => cmd.run(),
Generate(cmd) => cmd.run(),
ZebradCmd::Help(cmd) => cmd.run(),
Start(cmd) => cmd.run(),
TipHeight(cmd) => cmd.run(),
Version(cmd) => cmd.run(),
}
}
}

View File

@ -35,7 +35,7 @@
use std::{cmp::min, path::PathBuf};
use abscissa_core::{config, Command, FrameworkError, Options, Runnable};
use abscissa_core::{config, Command, FrameworkError, Runnable};
use color_eyre::eyre::{eyre, Report};
use tokio::time::Instant;
use tower::{Service, ServiceExt};
@ -45,6 +45,7 @@ use zebra_state as old_zs;
use zebra_state as new_zs;
use crate::{
application::ZebradApp,
components::tokio::{RuntimeRun, TokioComponent},
config::ZebradConfig,
prelude::*,
@ -54,11 +55,11 @@ use crate::{
/// How often we log info-level progress messages
const PROGRESS_HEIGHT_INTERVAL: u32 = 5_000;
/// `copy-state` subcommand
#[derive(Command, Debug, Options)]
/// copy cached chain state (expert users only)
#[derive(Command, Debug, clap::Parser)]
pub struct CopyStateCmd {
/// Source height that the copy finishes at.
#[options(help = "stop copying at this source height")]
#[clap(long, short, help = "stop copying at this source height")]
max_source_height: Option<u32>,
/// Path to a Zebra config.toml for the target state.
@ -66,26 +67,30 @@ pub struct CopyStateCmd {
///
/// Zebra only uses the state options from this config.
/// All other options are ignored.
#[options(help = "config file path for the target state (default: ephemeral), \
the source state uses the main zebrad config")]
#[clap(
long,
short,
help = "config file path for the target state (default: ephemeral), \
the source state uses the main zebrad config"
)]
target_config_path: Option<PathBuf>,
/// Filter strings which override the config file and defaults
#[options(free, help = "tracing filters which override the zebrad.toml config")]
#[clap(help = "tracing filters which override the zebrad.toml config")]
filters: Vec<String>,
}
impl CopyStateCmd {
/// Configure and launch the copy command
async fn start(&self) -> Result<(), Report> {
let base_config = app_config().clone();
let base_config = APPLICATION.config();
let source_config = base_config.state.clone();
// The default load_config impl doesn't actually modify the app config.
let target_config = self
.target_config_path
.as_ref()
.map(|path| app_writer().load_config(path))
.map(|path| ZebradApp::default().load_config(path))
.transpose()?
.map(|app_config| app_config.state)
.unwrap_or_else(new_zs::Config::ephemeral);
@ -394,9 +399,9 @@ impl Runnable for CopyStateCmd {
target_config_path = ?self.target_config_path,
"starting cached chain state copy"
);
let rt = app_writer()
.state_mut()
.components
let rt = APPLICATION
.state()
.components_mut()
.get_downcast_mut::<TokioComponent>()
.expect("TokioComponent should be available")
.rt

View File

@ -5,10 +5,10 @@
//! This command should be used if you're launching lots of `zebrad start` instances for testing,
//! or you want to include the parameter files in a distribution package.
use abscissa_core::{Command, Options, Runnable};
use abscissa_core::{Command, Runnable};
/// `download` subcommand
#[derive(Command, Debug, Default, Options)]
/// Pre-download required Zcash Sprout and Sapling parameter files
#[derive(Command, Debug, Default, clap::Parser)]
pub struct DownloadCmd {}
impl DownloadCmd {

View File

@ -0,0 +1,134 @@
//! Zebrad EntryPoint
use std::cmp::min;
use abscissa_core::{Command, Configurable, FrameworkError, Runnable};
use clap::Parser;
use std::{ffi::OsString, path::PathBuf};
use crate::config::ZebradConfig;
use super::ZebradCmd;
/// Toplevel entrypoint command.
///
/// Handles obtaining toplevel help as well as verbosity settings.
#[derive(Debug, clap::Parser)]
#[clap(
version = clap::crate_version!(),
author="Zcash Foundation <zebra@zfnd.org>",
help_template = "\
{name} {version}\n
{author}\n
{usage-heading} {usage}\n
{all-args}\
"
)]
pub struct EntryPoint {
/// Subcommand to execute.
///
/// The `command` option will delegate option parsing to the command type,
/// starting at the first free argument. Defaults to start.
#[clap(subcommand)]
pub cmd: Option<ZebradCmd>,
/// Path to the configuration file
#[clap(long, short, help = "path to configuration file")]
pub config: Option<PathBuf>,
/// Increase verbosity setting
#[clap(long, short, help = "be verbose")]
pub verbose: bool,
/// Filter strings which override the config file and defaults
// This can be applied to the default start command if no subcommand is provided.
#[clap(help = "tracing filters which override the zebrad.toml config")]
filters: Vec<String>,
}
impl EntryPoint {
/// Borrow the command in the option
///
/// # Panics
///
/// If `cmd` is None
pub fn cmd(&self) -> &ZebradCmd {
self.cmd
.as_ref()
.expect("should default to start if not provided")
}
/// Returns a string that parses to the default subcommand
pub fn default_cmd_as_str() -> &'static str {
"start"
}
/// Process command arguments and insert the default subcommand
/// if no subcommand is provided.
pub fn process_cli_args(mut args: Vec<OsString>) -> clap::error::Result<Vec<OsString>> {
// Check if the provided arguments include a subcommand
let should_add_default_subcommand = EntryPoint::try_parse_from(&args)?.cmd.is_none();
// Add the default subcommand to args after the top-level args if cmd is None
if should_add_default_subcommand {
// try_parse_from currently produces an error if the first argument is not the binary name,
let mut num_top_level_args = 1;
// update last_top_level_arg_idx to the number of top-level args
for (idx, arg) in args.iter().enumerate() {
num_top_level_args = match arg.to_str() {
Some("--verbose" | "-v" | "--version" | "-V" | "--help") => idx + 1,
Some("--config" | "-c") => idx + 2,
_ => num_top_level_args,
}
}
num_top_level_args = min(num_top_level_args, args.len());
args.insert(num_top_level_args, EntryPoint::default_cmd_as_str().into());
}
Ok(args)
}
}
impl Runnable for EntryPoint {
fn run(&self) {
self.cmd().run()
}
}
impl Command for EntryPoint {
/// Name of this program as a string
fn name() -> &'static str {
ZebradCmd::name()
}
/// Description of this program
fn description() -> &'static str {
ZebradCmd::description()
}
/// Authors of this program
fn authors() -> &'static str {
ZebradCmd::authors()
}
}
impl Configurable<ZebradConfig> for EntryPoint {
/// Path to the command's configuration file
fn config_path(&self) -> Option<PathBuf> {
match &self.config {
// Use explicit `-c`/`--config` argument if passed
Some(cfg) => Some(cfg.clone()),
// Otherwise defer to the toplevel command's config path logic
None => self.cmd().config_path(),
}
}
/// Process the configuration after it has been loaded, potentially
/// modifying it or returning an error if options are incompatible
fn process_config(&self, config: ZebradConfig) -> Result<ZebradConfig, FrameworkError> {
self.cmd().process_config(config)
}
}

View File

@ -1,13 +1,20 @@
//! `generate` subcommand - generates a skeleton config.
//! `generate` subcommand - generates a default `zebrad.toml` config.
use crate::config::ZebradConfig;
use abscissa_core::{Command, Options, Runnable};
use abscissa_core::{Command, Runnable};
use clap::Parser;
/// `generate` subcommand
#[derive(Command, Debug, Options)]
/// Generate a default `zebrad.toml` configuration
#[derive(Command, Debug, Default, Parser)]
pub struct GenerateCmd {
/// The file to write the generated config to.
#[options(help = "The file to write the generated config to (stdout if unspecified)")]
//
// TODO: use PathBuf here instead, to support non-UTF-8 paths
#[clap(
long,
short,
help = "The file to write the generated config to (stdout if unspecified)"
)]
output_file: Option<String>,
}

View File

@ -71,7 +71,7 @@
//!
//! Some of the diagnostic features are optional, and need to be enabled at compile-time.
use abscissa_core::{config, Command, FrameworkError, Options, Runnable};
use abscissa_core::{config, Command, FrameworkError, Runnable};
use color_eyre::eyre::{eyre, Report};
use futures::FutureExt;
use tokio::{pin, select, sync::oneshot};
@ -94,17 +94,17 @@ use crate::{
prelude::*,
};
/// `start` subcommand
#[derive(Command, Debug, Options, Default)]
/// Start the application (default command)
#[derive(Command, Debug, Default, clap::Parser)]
pub struct StartCmd {
/// Filter strings which override the config file and defaults
#[options(free, help = "tracing filters which override the zebrad.toml config")]
#[clap(help = "tracing filters which override the zebrad.toml config")]
filters: Vec<String>,
}
impl StartCmd {
async fn start(&self) -> Result<(), Report> {
let config = app_config().clone();
let config = APPLICATION.config();
info!("initializing node state");
let (_, max_checkpoint_height) = zebra_consensus::router::init_checkpoint_list(
@ -202,9 +202,9 @@ impl StartCmd {
// Launch RPC server
let (rpc_task_handle, rpc_tx_queue_task_handle, rpc_server) = RpcServer::spawn(
config.rpc,
config.rpc.clone(),
#[cfg(feature = "getblocktemplate-rpcs")]
config.mining,
config.mining.clone(),
#[cfg(not(feature = "getblocktemplate-rpcs"))]
(),
app_version(),
@ -428,7 +428,7 @@ impl StartCmd {
/// Returns the bound for the state service buffer,
/// based on the configurations of the services that use the state concurrently.
fn state_buffer_bound() -> usize {
let config = app_config().clone();
let config = APPLICATION.config();
// Ignore the checkpoint verify limit, because it is very large.
//
@ -450,9 +450,9 @@ impl Runnable for StartCmd {
/// Start the application.
fn run(&self) {
info!("Starting zebrad");
let rt = app_writer()
.state_mut()
.components
let rt = APPLICATION
.state()
.components_mut()
.get_downcast_mut::<TokioComponent>()
.expect("TokioComponent should be available")
.rt

View File

@ -0,0 +1,46 @@
//! Tests for parsing zebrad commands
use clap::Parser;
use crate::commands::ZebradCmd;
use super::EntryPoint;
#[test]
fn args_with_subcommand_pass_through() {
let test_cases = [
(false, true, false, vec!["zebrad"]),
(false, true, true, vec!["zebrad", "-v"]),
(false, true, true, vec!["zebrad", "--verbose"]),
(true, false, false, vec!["zebrad", "-h"]),
(true, false, false, vec!["zebrad", "--help"]),
(false, true, false, vec!["zebrad", "start"]),
(false, true, true, vec!["zebrad", "-v", "start"]),
(false, true, false, vec!["zebrad", "warn"]),
(false, true, false, vec!["zebrad", "start", "warn"]),
(true, false, false, vec!["zebrad", "help", "warn"]),
];
for (should_exit, should_be_start, should_be_verbose, args) in test_cases {
let args = EntryPoint::process_cli_args(args.iter().map(Into::into).collect());
if should_exit {
args.expect_err("parsing invalid args or 'help'/'--help' should return an error");
continue;
}
let args: Vec<std::ffi::OsString> = args.expect("args should parse into EntryPoint");
let args =
EntryPoint::try_parse_from(args).expect("hardcoded args should parse successfully");
assert!(args.config.is_none(), "args.config should be none");
assert!(args.cmd.is_some(), "args.cmd should not be none");
assert_eq!(
args.verbose, should_be_verbose,
"process_cli_args should preserve top-level args"
);
assert_eq!(matches!(args.cmd(), ZebradCmd::Start(_)), should_be_start,);
}
}

View File

@ -5,7 +5,8 @@
use std::path::PathBuf;
use abscissa_core::{Command, Options, Runnable};
use abscissa_core::{Application, Command, Runnable};
use clap::Parser;
use color_eyre::eyre::{eyre, Result};
use zebra_chain::{
@ -15,17 +16,17 @@ use zebra_chain::{
};
use zebra_state::LatestChainTip;
use crate::prelude::app_config;
use crate::prelude::APPLICATION;
/// `zebra-tip-height` subcommand
#[derive(Command, Debug, Options)]
/// Print the tip block height of Zebra's chain state on disk
#[derive(Command, Debug, Default, Parser)]
pub struct TipHeightCmd {
/// Path to Zebra's cached state.
#[options(help = "path to directory with the Zebra chain state")]
#[clap(long, short, help = "path to directory with the Zebra chain state")]
cache_dir: Option<PathBuf>,
/// The network to obtain the chain tip.
#[options(default = "mainnet", help = "the network of the chain to load")]
#[clap(long, short, help = "the network of the chain to load")]
network: Network,
}
@ -54,7 +55,7 @@ impl TipHeightCmd {
/// Starts a state service using the `cache_dir` and `network` from the provided arguments.
fn load_latest_chain_tip(&self) -> LatestChainTip {
let mut config = app_config().state.clone();
let mut config = APPLICATION.config().state.clone();
if let Some(cache_dir) = self.cache_dir.clone() {
config.cache_dir = cache_dir;

View File

@ -1,18 +0,0 @@
//! `version` subcommand
#![allow(clippy::never_loop)]
use super::ZebradCmd;
use abscissa_core::{Command, Options, Runnable};
/// `version` subcommand
#[derive(Command, Debug, Default, Options)]
pub struct VersionCmd {}
impl Runnable for VersionCmd {
/// Print version message
#[allow(clippy::print_stdout)]
fn run(&self) {
println!("{} {}", ZebradCmd::name(), ZebradCmd::version());
}
}

View File

@ -83,7 +83,7 @@ impl RuntimeRun for Runtime {
}
Err(error) => {
warn!(?error, "shutting down Zebra due to an error");
app_writer().shutdown(Shutdown::Forced);
APPLICATION.shutdown(Shutdown::Forced);
}
}
}

View File

@ -47,7 +47,7 @@ pub struct Tracing {
/// responsible for flushing any remaining logs when the program terminates.
//
// Correctness: must be listed last in the struct, so it drops after other drops have logged.
_guard: WorkerGuard,
_guard: Option<WorkerGuard>,
}
impl Tracing {
@ -94,7 +94,7 @@ impl Tracing {
// Builds a lossy NonBlocking logger with a default line limit of 128_000 or an explicit buffer_limit.
// The write method queues lines down a bounded channel with this capacity to a worker thread that writes to stdout.
// Increments error_counter and drops lines when the buffer is full.
let (non_blocking, _guard) = NonBlockingBuilder::default()
let (non_blocking, worker_guard) = NonBlockingBuilder::default()
.buffered_lines_limit(config.buffer_limit.max(100))
.finish(writer);
@ -275,10 +275,21 @@ impl Tracing {
initial_filter: filter,
#[cfg(feature = "flamegraph")]
flamegrapher,
_guard,
_guard: Some(worker_guard),
})
}
/// Drops guard for worker thread of non-blocking logger,
/// to flush any remaining logs when the program terminates.
pub fn shutdown(&mut self) {
self.filter_handle.take();
#[cfg(feature = "flamegraph")]
self.flamegrapher.take();
self._guard.take();
}
/// Return the currently-active tracing filter.
pub fn filter(&self) -> String {
if let Some(filter_handle) = self.filter_handle.as_ref() {

View File

@ -120,9 +120,9 @@ To set the filter, POST the new filter string to /filter:
(&Method::GET, "/filter") => Response::builder()
.status(StatusCode::OK)
.body(Body::from(
app_reader()
APPLICATION
.state()
.components
.components()
.get_downcast_ref::<Tracing>()
.expect("Tracing component should be available")
.filter(),
@ -130,9 +130,9 @@ To set the filter, POST the new filter string to /filter:
.expect("response with known status code cannot fail"),
(&Method::POST, "/filter") => match read_filter(req).await {
Ok(filter) => {
app_reader()
APPLICATION
.state()
.components
.components()
.get_downcast_ref::<Tracing>()
.expect("Tracing component should be available")
.reload_filter(filter);

View File

@ -2,7 +2,7 @@
//! which are generally useful and should be available everywhere.
/// Application state accessors
pub use crate::application::{app_config, app_reader, app_writer};
pub use crate::application::APPLICATION;
/// Commonly used Abscissa traits
pub use abscissa_core::{Application, Command, Runnable};

View File

@ -267,11 +267,11 @@ fn help_no_args() -> Result<()> {
is_zebrad_version,
&output.output.stdout,
"stdout",
"a valid zebrad semantic version",
"are valid zebrad semantic versions",
)?;
// Make sure we are in help by looking usage string
output.stdout_line_contains("USAGE:")?;
// Make sure we are in help by looking for the usage string
output.stdout_line_contains("Usage:")?;
Ok(())
}
@ -536,7 +536,7 @@ fn version_no_args() -> Result<()> {
let testdir = testdir()?.with_config(&mut default_test_config()?)?;
let child = testdir.spawn_child(args!["version"])?;
let child = testdir.spawn_child(args!["--version"])?;
let output = child.wait_with_output()?;
let output = output.assert_success()?;
@ -558,15 +558,23 @@ fn version_args() -> Result<()> {
let testdir = testdir()?.with_config(&mut default_test_config()?)?;
let testdir = &testdir;
// unexpected free argument `argument`
let child = testdir.spawn_child(args!["version", "argument"])?;
// unrecognized option `-f`
let child = testdir.spawn_child(args!["tip-height", "-f"])?;
let output = child.wait_with_output()?;
output.assert_failure()?;
// unrecognized option `-f`
let child = testdir.spawn_child(args!["version", "-f"])?;
// unrecognized option `-f` is ignored
let child = testdir.spawn_child(args!["--version", "-f"])?;
let output = child.wait_with_output()?;
output.assert_failure()?;
let output = output.assert_success()?;
// The output should only contain the version
output.output_check(
is_zebrad_version,
&output.output.stdout,
"stdout",
"a valid zebrad semantic version",
)?;
Ok(())
}