]> OzVa Git service - ozva-cloud/commitdiff
feat: add completions (#97)
authorsigoden <sigoden@gmail.com>
Wed, 6 Jul 2022 04:11:00 +0000 (12:11 +0800)
committerGitHub <noreply@github.com>
Wed, 6 Jul 2022 04:11:00 +0000 (12:11 +0800)
Cargo.lock
Cargo.toml
src/args.rs
src/main.rs
tests/args.rs
tests/cli.rs [new file with mode: 0644]

index 462486463f460f3a2db1dfce62acb27cb0adef31..1f7a8a4f139e605c971fcd781aec0d8d2fb1b65c 100644 (file)
@@ -234,6 +234,15 @@ dependencies = [
  "textwrap",
 ]
 
+[[package]]
+name = "clap_complete"
+version = "3.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ead064480dfc4880a10764488415a97fdd36a4cf1bb022d372f02e8faf8386e1"
+dependencies = [
+ "clap",
+]
+
 [[package]]
 name = "clap_lex"
 version = "0.2.4"
@@ -289,9 +298,9 @@ dependencies = [
 
 [[package]]
 name = "crypto-common"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
+checksum = "5999502d32b9c48d492abe66392408144895020ec4709e549e840799f3bb74c0"
 dependencies = [
  "generic-array",
  "typenum",
@@ -379,6 +388,7 @@ dependencies = [
  "base64",
  "chrono",
  "clap",
+ "clap_complete",
  "diqwest",
  "futures",
  "headers",
@@ -1087,9 +1097,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.12.0"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
+checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
 
 [[package]]
 name = "opaque-debug"
@@ -1431,9 +1441,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.5.6"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1448,9 +1458,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.26"
+version = "0.6.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 
 [[package]]
 name = "remove_dir_all"
index f0a735a3a00750e58c3dfa31e0596ad24f4273d1..9f6dfb30f866d94f7ac533b356304e9a03414a7a 100644 (file)
@@ -12,6 +12,7 @@ keywords = ["static", "file", "server", "webdav", "cli"]
 
 [dependencies]
 clap = { version = "3", default-features = false, features = ["std", "wrap_help"] }
+clap_complete = "3"
 chrono = "0.4"
 tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"]}
 tokio-util = { version = "0.7",  features = ["io-util"] }
index 11fbfe10bf5a2630b07e712a4af017648ca7a919..e9efc6dcdd2602ebf6fdcd735db62aed102e99c5 100644 (file)
@@ -1,4 +1,5 @@
-use clap::{AppSettings, Arg, ArgMatches, Command};
+use clap::{value_parser, AppSettings, Arg, ArgMatches, Command};
+use clap_complete::{generate, Generator, Shell};
 #[cfg(feature = "tls")]
 use rustls::{Certificate, PrivateKey};
 use std::env;
@@ -11,7 +12,7 @@ use crate::auth::AuthMethod;
 use crate::tls::{load_certs, load_private_key};
 use crate::BoxResult;
 
-fn app() -> Command<'static> {
+pub fn build_cli() -> Command<'static> {
     let app = Command::new(env!("CARGO_CRATE_NAME"))
         .version(env!("CARGO_PKG_VERSION"))
         .author(env!("CARGO_PKG_AUTHORS"))
@@ -118,6 +119,13 @@ fn app() -> Command<'static> {
             Arg::new("render-spa")
                 .long("render-spa")
                 .help("Serve SPA(Single Page Application)"),
+        )
+        .arg(
+            Arg::new("completions")
+                .long("completions")
+                .value_name("shell")
+                .value_parser(value_parser!(Shell))
+                .help("Print shell completion script for <shell>"),
         );
 
     #[cfg(feature = "tls")]
@@ -138,8 +146,8 @@ fn app() -> Command<'static> {
     app
 }
 
-pub fn matches() -> ArgMatches {
-    app().get_matches()
+pub fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
+    generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
 }
 
 #[derive(Debug)]
index 9a2ed24969b7c534d22ea80a91a9f5fa37e8b9f0..c3a120b5bb45178b704e5edff5e0b50751848ba2 100644 (file)
@@ -10,7 +10,7 @@ mod utils;
 #[macro_use]
 extern crate log;
 
-use crate::args::{matches, Args};
+use crate::args::{build_cli, print_completions, Args};
 use crate::server::{Request, Server};
 #[cfg(feature = "tls")]
 use crate::tls::{TlsAcceptor, TlsStream};
@@ -19,6 +19,7 @@ use std::net::{IpAddr, SocketAddr, TcpListener as StdTcpListener};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
 
+use clap_complete::Shell;
 use futures::future::join_all;
 use tokio::net::TcpListener;
 use tokio::task::JoinHandle;
@@ -37,7 +38,14 @@ async fn main() {
 
 async fn run() -> BoxResult<()> {
     logger::init().map_err(|e| format!("Failed to init logger, {}", e))?;
-    let args = Args::parse(matches())?;
+    let cmd = build_cli();
+    let matches = cmd.get_matches();
+    if let Some(generator) = matches.get_one::<Shell>("completions") {
+        let mut cmd = build_cli();
+        print_completions(*generator, &mut cmd);
+        return Ok(());
+    }
+    let args = Args::parse(matches)?;
     let args = Arc::new(args);
     let running = Arc::new(AtomicBool::new(true));
     let handles = serve(args.clone(), running.clone())?;
index 83086e965d0b1ca890fa721619b55b8b0d755578..db6180325abce741fd3bf126c98b3d50618f2901 100644 (file)
@@ -1,3 +1,5 @@
+//! Run file server with different args
+
 mod fixtures;
 mod utils;
 
diff --git a/tests/cli.rs b/tests/cli.rs
new file mode 100644 (file)
index 0000000..01b02b6
--- /dev/null
@@ -0,0 +1,32 @@
+//! Run cli with different args, not starting a server
+
+mod fixtures;
+
+use assert_cmd::prelude::*;
+use clap::ValueEnum;
+use clap_complete::Shell;
+use fixtures::Error;
+use std::process::Command;
+
+#[test]
+/// Show help and exit.
+fn help_shows() -> Result<(), Error> {
+    Command::cargo_bin("dufs")?.arg("-h").assert().success();
+
+    Ok(())
+}
+
+#[test]
+/// Print completions and exit.
+fn print_completions() -> Result<(), Error> {
+    // let shell_enums = EnumValueParser::<Shell>::new();
+    for shell in Shell::value_variants() {
+        Command::cargo_bin("dufs")?
+            .arg("--completions")
+            .arg(shell.to_string())
+            .assert()
+            .success();
+    }
+
+    Ok(())
+}