From b6fa63c63a6700023ceaa70d1dd31ef241f53270 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 25 Nov 2022 15:16:50 +0100 Subject: [PATCH 1/3] Update to axum 0.6.0 --- Cargo.lock | 34 ++++++++++++++++++++++++++-------- Cargo.toml | 2 +- src/proxy.rs | 28 ++++++++++------------------ src/serve.rs | 9 ++++----- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0750fb8c..d5a0af14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.16" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e3356844c4d6a6d6467b8da2cffb4a2820be256f50a3a386c9d152bab31043" +checksum = "744864363a200a5e724a7e61bc8c11b6628cf2e3ec519c8a1a48e609a8156b40" dependencies = [ "async-trait", "axum-core", @@ -84,8 +84,10 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustversion", "serde", "serde_json", + "serde_path_to_error", "serde_urlencoded", "sha-1", "sync_wrapper", @@ -99,9 +101,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f0c0a60006f2a293d82d571f635042a72edf927539b7685bd62d361963839b" +checksum = "79b8558f5a0581152dc94dcd289132a1d377494bdeafcd41869b3258e3e2ad92" dependencies = [ "async-trait", "bytes", @@ -109,6 +111,7 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", "tower-layer", "tower-service", ] @@ -1088,9 +1091,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "matchit" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "3dfc802da7b1cf80aefffa0c7b2f77247c8b32206cc83c270b61264f5b360a80" [[package]] name = "memchr" @@ -1790,6 +1793,12 @@ dependencies = [ "base64", ] +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + [[package]] name = "ryu" version = "1.0.11" @@ -1887,6 +1896,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "184c643044780f7ceb59104cef98a5a6f12cb2288a7bc701ab93a362b49fd47d" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2321,9 +2339,9 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" diff --git a/Cargo.toml b/Cargo.toml index 0af9876e..9862f300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ panic = "abort" [dependencies] ansi_term = "0.12" anyhow = "1" -axum = { version = "0.5", features = ["ws"] } +axum = { version = "0.6", features = ["ws"] } bytes = "1" cargo-lock = "8" cargo_metadata = "0.15" diff --git a/src/proxy.rs b/src/proxy.rs index 5de3ec2d..13594a7c 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,13 +1,12 @@ use std::sync::Arc; use anyhow::Context; +use axum::RequestExt; use axum::body::Body; use axum::extract::ws::{Message as MsgAxm, WebSocket, WebSocketUpgrade}; -use axum::extract::{Extension, FromRequest, RequestParts}; -use axum::handler::Handler; +use axum::extract::State; use axum::http::{Request, Response, Uri}; use axum::routing::{any, get, Router}; -//use axum::AddExtensionLayer; use futures_util::sink::SinkExt; use futures_util::stream::StreamExt; use reqwest::header::HeaderValue; @@ -73,11 +72,11 @@ impl ProxyHandlerHttp { /// Build the sub-router for this proxy. pub fn register(self: Arc, router: Router) -> Router { - router.nest( + router.nest_service( self.path(), - any(Self::proxy_http_request - .layer(Extension(self.clone())) - .layer(TraceLayer::new_for_http())), + any(Self::proxy_http_request) + .layer(TraceLayer::new_for_http()) + .with_state(self.clone()) ) } @@ -89,14 +88,8 @@ impl ProxyHandlerHttp { } /// Proxy the given request to the target backend. - #[tracing::instrument(level = "debug", skip(req))] - async fn proxy_http_request(req: Request) -> ServerResult> { - let state = req - .extensions() - .get::>() - .cloned() - .context("error accessing proxy handler state")?; - + #[tracing::instrument(level = "debug", skip(state, req))] + async fn proxy_http_request(State(state): State>, req: Request) -> ServerResult> { // Construct the outbound URI & build a new request to be sent to the proxy backend. let outbound_uri = make_outbound_uri(&state.backend, req.uri())?; let mut outbound_req = state @@ -149,12 +142,11 @@ impl ProxyHandlerWebSocket { /// Build the sub-router for this proxy. pub fn register(self: Arc, router: Router) -> Router { let proxy = self.clone(); - router.nest( + router.nest_service( self.path(), get(|req: Request| async move { let uri = req.uri().clone(); - let mut parts = RequestParts::new(req); - let ws = WebSocketUpgrade::from_request(&mut parts).await; + let ws = req.extract::().await; ws.map(|e| { e.on_upgrade(|socket| async move { proxy.clone().proxy_ws_request(socket, uri).await diff --git a/src/serve.rs b/src/serve.rs index 1ce51415..402174a0 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use anyhow::{Context, Result}; use axum::body::{self, Body}; use axum::extract::ws::{WebSocket, WebSocketUpgrade}; -use axum::extract::Extension; use axum::http::StatusCode; use axum::response::Response; use axum::routing::{get, get_service, Router}; @@ -184,8 +183,8 @@ fn router(state: Arc, cfg: Arc) -> Router { }; let mut router = Router::new() - .fallback( - Router::new().nest( + .fallback_service( + Router::new().nest_service( public_route, get_service( ServeDir::new(&state.dist_dir) @@ -201,12 +200,12 @@ fn router(state: Arc, cfg: Arc) -> Router { .route( "/_trunk/ws", get( - |ws: WebSocketUpgrade, state: Extension>| async move { + |ws: WebSocketUpgrade, state: axum::extract::State>| async move { ws.on_upgrade(|socket| async move { handle_ws(socket, state.0).await }) }, ), ) - .layer(Extension(state.clone())); + .with_state(state.clone()); tracing::info!( "{} serving static assets at -> {}", From 385521cf6f348198ec2a34367bea240010ec49ec Mon Sep 17 00:00:00 2001 From: Anthony Dodd Date: Mon, 28 Nov 2022 10:39:06 -0600 Subject: [PATCH 2/3] Update CI to no longer deny linter warnings This can be a bit of a difficulty for folks opening PRs and then the linter complains about completely unrelated code and denies their PR. Instead, we continue to warn about these issues, but we do not block CI. --- .github/workflows/ci.yaml | 2 +- CHANGELOG.md | 1 + src/proxy.rs | 9 ++++++--- src/tools.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6e06ad0c..7635ec2c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,7 +29,7 @@ jobs: uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - args: --all-targets -- -D warnings + args: --all-targets - name: Setup | Toolchain (rustfmt) uses: actions-rs/toolchain@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index d26fe2e6..ed963260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe - Updated gloo-worker example to use gloo-worker crate v2.1. - Our website (trunkrs.dev) now only updates on new releases. - Additional attributes are now passed through script tags (fixes #429) +- Updated internal http stack to axum v0.6.0. ### fixed - Nested WS proxies - if `backend=ws://localhost:8000/ws` is set, queries for `ws://localhost:8080/ws/entityX` will be linked with `ws://localhost:8000/ws/entityX` - Updated all dependencies in both Trunk and its examples, to fix currently open security advisories for old dependencies. diff --git a/src/proxy.rs b/src/proxy.rs index 13594a7c..9aaa0e61 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,12 +1,12 @@ use std::sync::Arc; use anyhow::Context; -use axum::RequestExt; use axum::body::Body; use axum::extract::ws::{Message as MsgAxm, WebSocket, WebSocketUpgrade}; use axum::extract::State; use axum::http::{Request, Response, Uri}; use axum::routing::{any, get, Router}; +use axum::RequestExt; use futures_util::sink::SinkExt; use futures_util::stream::StreamExt; use reqwest::header::HeaderValue; @@ -76,7 +76,7 @@ impl ProxyHandlerHttp { self.path(), any(Self::proxy_http_request) .layer(TraceLayer::new_for_http()) - .with_state(self.clone()) + .with_state(self.clone()), ) } @@ -89,7 +89,10 @@ impl ProxyHandlerHttp { /// Proxy the given request to the target backend. #[tracing::instrument(level = "debug", skip(state, req))] - async fn proxy_http_request(State(state): State>, req: Request) -> ServerResult> { + async fn proxy_http_request( + State(state): State>, + req: Request, + ) -> ServerResult> { // Construct the outbound URI & build a new request to be sent to the proxy backend. let outbound_uri = make_outbound_uri(&state.backend, req.uri())?; let mut outbound_req = state diff --git a/src/tools.rs b/src/tools.rs index 69df2236..23327dfb 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -263,7 +263,7 @@ async fn find_system(app: Application, version: Option<&str>) -> Option<(PathBuf Ok((path, system_version)) => version .map(|v| v == system_version) .unwrap_or(true) - .then(|| (path, system_version)), + .then_some((path, system_version)), Err(e) => { tracing::debug!("system version not found for {}: {}", app.name(), e); None From b41a9575d441ab5d0cea2110a1de92146bdd25e4 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 21 Dec 2022 11:01:29 +0900 Subject: [PATCH 3/3] Update clap to v4 (#471) --- CHANGELOG.md | 1 + Cargo.lock | 20 ++++++-------------- Cargo.toml | 2 +- src/cmd/build.rs | 4 ++-- src/cmd/clean.rs | 6 +++--- src/cmd/config.rs | 4 ++-- src/cmd/serve.rs | 8 ++++---- src/cmd/watch.rs | 6 +++--- src/common.rs | 5 +++-- src/config/models.rs | 45 ++++++++++++++++++++++---------------------- src/main.rs | 19 +++++++++++++++---- 11 files changed, 62 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed963260..34e1d9aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe - Our website (trunkrs.dev) now only updates on new releases. - Additional attributes are now passed through script tags (fixes #429) - Updated internal http stack to axum v0.6.0. +- Updated CLI argument parser to clap v0.4. ### fixed - Nested WS proxies - if `backend=ws://localhost:8000/ws` is set, queries for `ws://localhost:8080/ws/entityX` will be linked with `ws://localhost:8000/ws/entityX` - Updated all dependencies in both Trunk and its examples, to fix currently open security advisories for old dependencies. diff --git a/Cargo.lock b/Cargo.lock index d5a0af14..5b3b521f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,26 +257,24 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.22" +version = "4.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", "once_cell", "strsim", "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck", "proc-macro-error", @@ -287,9 +285,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -2131,12 +2129,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "textwrap" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" - [[package]] name = "thin-slice" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 9862f300..5ec70fd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ axum = { version = "0.6", features = ["ws"] } bytes = "1" cargo-lock = "8" cargo_metadata = "0.15" -clap = { version = "3", features = ["derive", "env"] } +clap = { version = "4", features = ["derive", "env"] } console = "0.15" directories = "4" dunce = "1" diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 5ddde856..5cc7dd2c 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -8,9 +8,9 @@ use crate::config::{ConfigOpts, ConfigOptsBuild}; /// Build the Rust WASM app and all of its assets. #[derive(Clone, Debug, Args)] -#[clap(name = "build")] +#[command(name = "build")] pub struct Build { - #[clap(flatten)] + #[command(flatten)] pub build: ConfigOptsBuild, } diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index d5eb7ece..28e6557a 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -11,15 +11,15 @@ use crate::tools::cache_dir; /// Clean output artifacts. #[derive(Args)] -#[clap(name = "clean")] +#[command(name = "clean")] pub struct Clean { - #[clap(flatten)] + #[command(flatten)] pub clean: ConfigOptsClean, /// Optionally clean any cached tools used by Trunk /// /// These tools are cached in a platform dependent "projects" dir. Removing them will cause /// them to be downloaded by Trunk next time they are needed. - #[clap(short, long)] + #[arg(short, long)] pub tools: bool, } diff --git a/src/cmd/config.rs b/src/cmd/config.rs index 8e530620..2d43b76a 100644 --- a/src/cmd/config.rs +++ b/src/cmd/config.rs @@ -7,9 +7,9 @@ use crate::config::ConfigOpts; /// Trunk config controls. #[derive(Clone, Debug, Args)] -#[clap(name = "config")] +#[command(name = "config")] pub struct Config { - #[clap(subcommand)] + #[command(subcommand)] action: ConfigSubcommands, } diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 9887d884..7d38e9e4 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -9,13 +9,13 @@ use crate::serve::ServeSystem; /// Build, watch & serve the Rust WASM app and all of its assets. #[derive(Args)] -#[clap(name = "serve")] +#[command(name = "serve")] pub struct Serve { - #[clap(flatten)] + #[command(flatten)] pub build: ConfigOptsBuild, - #[clap(flatten)] + #[command(flatten)] pub watch: ConfigOptsWatch, - #[clap(flatten)] + #[command(flatten)] pub serve: ConfigOptsServe, } diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 1c893df8..8ff6a7c7 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -9,11 +9,11 @@ use crate::watch::WatchSystem; /// Build & watch the Rust WASM app and all of its assets. #[derive(Args)] -#[clap(name = "watch")] +#[command(name = "watch")] pub struct Watch { - #[clap(flatten)] + #[command(flatten)] pub build: ConfigOptsBuild, - #[clap(flatten)] + #[command(flatten)] pub watch: ConfigOptsWatch, } diff --git a/src/common.rs b/src/common.rs index 6bb93555..dd92e715 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,5 +1,6 @@ //! Common functionality and types. +use std::convert::Infallible; use std::ffi::OsStr; use std::fmt::Debug; use std::fs::Metadata; @@ -22,10 +23,10 @@ static CWD: Lazy = Lazy::new(|| std::env::current_dir().expect("error getting current dir")); /// Ensure the given value for `--public-url` is formatted correctly. -pub fn parse_public_url(val: &str) -> String { +pub fn parse_public_url(val: &str) -> Result { let prefix = if !val.starts_with('/') { "/" } else { "" }; let suffix = if !val.ends_with('/') { "/" } else { "" }; - format!("{}{}{}", prefix, val, suffix) + Ok(format!("{}{}{}", prefix, val, suffix)) } /// A utility function to recursively copy a directory. diff --git a/src/config/models.rs b/src/config/models.rs index 6f9003ae..f60becb7 100644 --- a/src/config/models.rs +++ b/src/config/models.rs @@ -17,32 +17,31 @@ use crate::pipelines::PipelineStage; #[derive(Clone, Debug, Default, Deserialize, Args)] pub struct ConfigOptsBuild { /// The index HTML file to drive the bundling process [default: index.html] - #[clap(parse(from_os_str))] pub target: Option, /// Build in release mode [default: false] - #[clap(long)] + #[arg(long)] #[serde(default)] pub release: bool, /// The output dir for all final assets [default: dist] - #[clap(short, long, parse(from_os_str))] + #[arg(short, long)] pub dist: Option, /// The public URL from which assets are to be served [default: /] - #[clap(long, parse(from_str=parse_public_url))] + #[arg(long, value_parser = parse_public_url)] pub public_url: Option, /// Build without default features [default: false] - #[clap(long)] + #[arg(long)] #[serde(default)] pub no_default_features: bool, /// Build with all features [default: false] - #[clap(long)] + #[arg(long)] #[serde(default)] pub all_features: bool, /// A comma-separated list of features to activate, must not be used with all-features /// [default: ""] - #[clap(long)] + #[arg(long)] pub features: Option, /// Whether to include hash values in the output file names [default: true] - #[clap(long)] + #[arg(long)] pub filehash: Option, /// Optional pattern for the app loader script [default: None] /// @@ -51,7 +50,7 @@ pub struct ConfigOptsBuild { /// to key/value pairs provided in `pattern_params`. /// /// These values can only be provided via config file. - #[clap(skip)] + #[arg(skip)] #[serde(default)] pub pattern_script: Option, /// Optional pattern for the app preload element [default: None] @@ -61,10 +60,10 @@ pub struct ConfigOptsBuild { /// to key/value pairs provided in `pattern_params`. /// /// These values can only be provided via config file. - #[clap(skip)] + #[arg(skip)] #[serde(default)] pub pattern_preload: Option, - #[clap(skip)] + #[arg(skip)] #[serde(default)] /// Optional replacement parameters corresponding to the patterns provided in /// `pattern_script` and `pattern_preload`. @@ -86,10 +85,10 @@ pub struct ConfigOptsBuild { #[derive(Clone, Debug, Default, Deserialize, Args)] pub struct ConfigOptsWatch { /// Watch specific file(s) or folder(s) [default: build target parent folder] - #[clap(short, long, parse(from_os_str), value_name = "path")] + #[arg(short, long, value_name = "path")] pub watch: Option>, /// Paths to ignore [default: []] - #[clap(short, long, parse(from_os_str), value_name = "path")] + #[arg(short, long, value_name = "path")] pub ignore: Option>, } @@ -97,34 +96,34 @@ pub struct ConfigOptsWatch { #[derive(Clone, Debug, Default, Deserialize, Args)] pub struct ConfigOptsServe { /// The address to serve on [default: 127.0.0.1] - #[clap(long)] + #[arg(long)] pub address: Option, /// The port to serve on [default: 8080] - #[clap(long)] + #[arg(long)] pub port: Option, /// Open a browser tab once the initial build is complete [default: false] - #[clap(long)] + #[arg(long)] #[serde(default)] pub open: bool, /// A URL to which requests will be proxied [default: None] - #[clap(long = "proxy-backend")] + #[arg(long = "proxy-backend")] #[serde(default, deserialize_with = "deserialize_uri")] pub proxy_backend: Option, /// The URI on which to accept requests which are to be rewritten and proxied to backend /// [default: None] - #[clap(long = "proxy-rewrite")] + #[arg(long = "proxy-rewrite")] #[serde(default)] pub proxy_rewrite: Option, /// Configure the proxy for handling WebSockets [default: false] - #[clap(long = "proxy-ws")] + #[arg(long = "proxy-ws")] #[serde(default)] pub proxy_ws: bool, /// Configure the proxy to accept insecure requests [default: false] - #[clap(long = "proxy-insecure")] + #[arg(long = "proxy-insecure")] #[serde(default)] pub proxy_insecure: bool, /// Disable auto-reload of the web app [default: false] - #[clap(long = "no-autoreload")] + #[arg(long = "no-autoreload")] #[serde(default)] pub no_autoreload: bool, } @@ -133,10 +132,10 @@ pub struct ConfigOptsServe { #[derive(Clone, Debug, Default, Deserialize, Args)] pub struct ConfigOptsClean { /// The output dir for all final assets [default: dist] - #[clap(short, long, parse(from_os_str))] + #[arg(short, long)] pub dist: Option, /// Optionally perform a cargo clean [default: false] - #[clap(long)] + #[arg(long)] #[serde(default)] pub cargo: bool, } diff --git a/src/main.rs b/src/main.rs index d33445a1..c7bd49a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,15 +49,15 @@ async fn main() -> Result<()> { /// Build, bundle & ship your Rust WASM application to the web. #[derive(Parser)] -#[clap(about, author, version, name = "trunk")] +#[command(about, author, version, name = "trunk")] struct Trunk { - #[clap(subcommand)] + #[command(subcommand)] action: TrunkSubcommands, /// Path to the Trunk config file [default: Trunk.toml] - #[clap(long, parse(from_os_str), env = "TRUNK_CONFIG")] + #[arg(long, env = "TRUNK_CONFIG")] pub config: Option, /// Enable verbose logging. - #[clap(short)] + #[arg(short)] pub v: bool, } @@ -87,3 +87,14 @@ enum TrunkSubcommands { /// Trunk config controls. Config(cmd::config::Config), } + +#[cfg(test)] +mod tests { + use crate::Trunk; + + #[test] + fn verify_cli() { + use clap::CommandFactory; + Trunk::command().debug_assert(); + } +}