aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhai Can <bczhc0@126.com>2023-11-10 20:13:03 +0800
committerZhai Can <bczhc0@126.com>2023-11-10 21:20:01 +0800
commit1d1fe7b0b68719263ea31504e74c2b0f5ad2e053 (patch)
tree7679e8685b022b35371389f298aab6557bffa923
parent61134a06fa714f32a405680d3515af94dfa11d2c (diff)
downloadbcachefs-tools-1d1fe7b0b68719263ea31504e74c2b0f5ad2e053.tar.gz
add command to generate Rust-part CLI completions
-rw-r--r--bcachefs.c5
-rw-r--r--cmds.h3
-rw-r--r--rust-src/Cargo.lock10
-rw-r--r--rust-src/Cargo.toml1
-rw-r--r--rust-src/src/cmd_completions.rs24
-rw-r--r--rust-src/src/cmd_list.rs21
-rw-r--r--rust-src/src/cmd_mount.rs13
-rw-r--r--rust-src/src/lib.rs29
8 files changed, 85 insertions, 21 deletions
diff --git a/bcachefs.c b/bcachefs.c
index 827996f8..4efe29ed 100644
--- a/bcachefs.c
+++ b/bcachefs.c
@@ -97,6 +97,9 @@ static void usage(void)
" fusemount Mount a filesystem via FUSE\n"
"\n"
"Miscellaneous:\n"
+#ifndef BCACHEFS_NO_RUST
+ " completions Generate shell completions\n"
+#endif
" version Display the version of the invoked bcachefs tool\n");
}
@@ -273,6 +276,8 @@ int main(int argc, char *argv[])
#ifndef BCACHEFS_NO_RUST
if (!strcmp(cmd, "mount"))
return cmd_mount(argc, argv);
+ if (strstr(cmd, "completions"))
+ return cmd_completions(argc, argv);
#endif
#ifdef BCACHEFS_FUSE
diff --git a/cmds.h b/cmds.h
index 8b567953..ad810ab3 100644
--- a/cmds.h
+++ b/cmds.h
@@ -60,6 +60,7 @@ int cmd_subvolume_delete(int argc, char *argv[]);
int cmd_subvolume_snapshot(int argc, char *argv[]);
int cmd_fusemount(int argc, char *argv[]);
-int cmd_mount(int agc, char *argv[]);
+int cmd_mount(int argc, char *argv[]);
+int cmd_completions(int argc, char *argv[]);
#endif /* _CMDS_H */
diff --git a/rust-src/Cargo.lock b/rust-src/Cargo.lock
index f43cc63c..d270cb41 100644
--- a/rust-src/Cargo.lock
+++ b/rust-src/Cargo.lock
@@ -93,6 +93,7 @@ dependencies = [
"byteorder",
"chrono",
"clap",
+ "clap_complete",
"colored",
"either",
"errno 0.2.8",
@@ -238,6 +239,15 @@ dependencies = [
]
[[package]]
+name = "clap_complete"
+version = "4.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae"
+dependencies = [
+ "clap",
+]
+
+[[package]]
name = "clap_derive"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/rust-src/Cargo.toml b/rust-src/Cargo.toml
index b490400c..e88c05fe 100644
--- a/rust-src/Cargo.toml
+++ b/rust-src/Cargo.toml
@@ -14,6 +14,7 @@ log = { version = "0.4", features = ["std"] }
chrono = { version = "0.4", default-features = false }
colored = "2"
clap = { version = "4.0.32", features = ["derive", "wrap_help"] }
+clap_complete = "4.4.4"
anyhow = "1.0"
libc = "0.2.69"
udev = "0.7.0"
diff --git a/rust-src/src/cmd_completions.rs b/rust-src/src/cmd_completions.rs
new file mode 100644
index 00000000..51859696
--- /dev/null
+++ b/rust-src/src/cmd_completions.rs
@@ -0,0 +1,24 @@
+use crate::transform_c_args;
+use clap::{Command, CommandFactory, Parser};
+use clap_complete::{generate, Generator, Shell};
+use std::ffi::{c_char, c_int};
+use std::io;
+
+/// Generate shell completions
+#[derive(clap::Parser, Debug)]
+pub struct Cli {
+ shell: Shell,
+}
+
+fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
+ generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
+}
+
+#[no_mangle]
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
+pub extern "C" fn cmd_completions(argc: c_int, argv: *const *const c_char) -> c_int {
+ transform_c_args!(argv, argc, argv);
+ let cli = Cli::parse_from(argv);
+ print_completions(cli.shell, &mut super::Cli::command());
+ 0
+}
diff --git a/rust-src/src/cmd_list.rs b/rust-src/src/cmd_list.rs
index 3f86b8cd..574f7cee 100644
--- a/rust-src/src/cmd_list.rs
+++ b/rust-src/src/cmd_list.rs
@@ -8,9 +8,9 @@ use bch_bindgen::btree::BtreeTrans;
use bch_bindgen::btree::BtreeIter;
use bch_bindgen::btree::BtreeNodeIter;
use bch_bindgen::btree::BtreeIterFlags;
-use clap::Parser;
-use std::ffi::{CStr, OsStr, c_int, c_char};
-use std::os::unix::ffi::OsStrExt;
+use clap::{Args, Parser};
+use std::ffi::{c_int, c_char};
+use crate::transform_c_args;
fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
let trans = BtreeTrans::new(fs);
@@ -84,7 +84,7 @@ fn list_nodes_ondisk(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
Ok(())
}
-#[derive(Clone, clap::ValueEnum)]
+#[derive(Clone, clap::ValueEnum, Debug)]
enum Mode {
Keys,
Formats,
@@ -92,8 +92,8 @@ enum Mode {
NodesOndisk,
}
-#[derive(Parser)]
-struct Cli {
+#[derive(Parser, Debug)]
+pub struct Cli {
/// Btree to list from
#[arg(short, long, default_value_t=bcachefs::btree_id::BTREE_ID_extents)]
btree: bcachefs::btree_id,
@@ -120,7 +120,7 @@ struct Cli {
/// Force color on/off. Default: autodetect tty
#[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))]
colorize: bool,
-
+
/// Verbose mode
#[arg(short, long)]
verbose: bool,
@@ -157,12 +157,9 @@ fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> {
}
#[no_mangle]
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn cmd_list(argc: c_int, argv: *const *const c_char) {
- let argv: Vec<_> = (0..argc)
- .map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) })
- .map(|i| OsStr::from_bytes(i.to_bytes()))
- .collect();
-
+ transform_c_args!(argv, argc, argv);
let opt = Cli::parse_from(argv);
colored::control::set_override(opt.colorize);
if let Err(e) = cmd_list_inner(opt) {
diff --git a/rust-src/src/cmd_mount.rs b/rust-src/src/cmd_mount.rs
index f7c6d920..9d58cb3e 100644
--- a/rust-src/src/cmd_mount.rs
+++ b/rust-src/src/cmd_mount.rs
@@ -1,10 +1,10 @@
use atty::Stream;
use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle};
use log::{info, debug, error, LevelFilter};
-use clap::Parser;
+use clap::{Parser, Subcommand};
use uuid::Uuid;
use std::path::PathBuf;
-use crate::key;
+use crate::{key, transform_c_args};
use crate::key::KeyLoc;
use crate::logger::SimpleLogger;
use std::ffi::{CStr, CString, OsStr, c_int, c_char, c_void};
@@ -129,7 +129,7 @@ fn get_devices_by_uuid(uuid: Uuid) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle
/// Mount a bcachefs filesystem by its UUID.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
-struct Cli {
+pub struct Cli {
/// Where the password would be loaded from.
///
/// Possible values are:
@@ -228,12 +228,9 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> {
}
#[no_mangle]
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn cmd_mount(argc: c_int, argv: *const *const c_char) -> c_int {
- let argv: Vec<_> = (0..argc)
- .map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) })
- .map(|i| OsStr::from_bytes(i.to_bytes()))
- .collect();
-
+ transform_c_args!(argv, argc, argv);
let opt = Cli::parse_from(argv);
log::set_boxed_logger(Box::new(SimpleLogger)).unwrap();
diff --git a/rust-src/src/lib.rs b/rust-src/src/lib.rs
index 159d049d..64297b41 100644
--- a/rust-src/src/lib.rs
+++ b/rust-src/src/lib.rs
@@ -1,7 +1,24 @@
+use clap::Subcommand;
+
pub mod key;
pub mod logger;
pub mod cmd_mount;
pub mod cmd_list;
+pub mod cmd_completions;
+
+#[derive(clap::Parser, Debug)]
+#[command(name = "bcachefs")]
+pub struct Cli {
+ #[command(subcommand)]
+ subcommands: Subcommands,
+}
+
+#[derive(Subcommand, Debug)]
+enum Subcommands {
+ List(cmd_list::Cli),
+ Mount(cmd_mount::Cli),
+ Completions(cmd_completions::Cli),
+}
#[macro_export]
macro_rules! c_str {
@@ -14,6 +31,18 @@ macro_rules! c_str {
};
}
+#[macro_export]
+macro_rules! transform_c_args {
+ ($var:ident, $argc:expr, $argv:expr) => {
+ // TODO: `OsStr::from_bytes` only exists on *nix
+ use ::std::os::unix::ffi::OsStrExt;
+ let $var: Vec<_> = (0..$argc)
+ .map(|i| unsafe { ::std::ffi::CStr::from_ptr(*$argv.add(i as usize)) })
+ .map(|i| ::std::ffi::OsStr::from_bytes(i.to_bytes()))
+ .collect();
+ };
+}
+
#[derive(Debug)]
struct ErrnoError(errno::Errno);
impl std::fmt::Display for ErrnoError {