Skip to content

Commit 68a75da

Browse files
authored
Merge pull request #1844 from wendajiang/master
Upgrade clap
2 parents 0b2520f + 87a381e commit 68a75da

13 files changed

+180
-209
lines changed

Cargo.lock

+18-26
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ rust-version = "1.60"
1919
[dependencies]
2020
anyhow = "1.0.28"
2121
chrono = "0.4"
22-
clap = { version = "3.0", features = ["cargo"] }
23-
clap_complete = "3.0"
22+
clap = { version = "4.0.29", features = ["cargo", "wrap_help"] }
23+
clap_complete = "4.0.6"
2424
once_cell = "1"
2525
env_logger = "0.10.0"
2626
handlebars = "4.0"

examples/nop-preprocessor.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use crate::nop_lib::Nop;
2-
use clap::{App, Arg, ArgMatches};
2+
use clap::{Arg, ArgMatches, Command};
33
use mdbook::book::Book;
44
use mdbook::errors::Error;
55
use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext};
66
use semver::{Version, VersionReq};
77
use std::io;
88
use std::process;
99

10-
pub fn make_app() -> App<'static> {
11-
App::new("nop-preprocessor")
10+
pub fn make_app() -> Command {
11+
Command::new("nop-preprocessor")
1212
.about("A mdbook preprocessor which does precisely nothing")
1313
.subcommand(
14-
App::new("supports")
14+
Command::new("supports")
1515
.arg(Arg::new("renderer").required(true))
1616
.about("Check whether a renderer is supported by this preprocessor"),
1717
)
@@ -54,7 +54,9 @@ fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> {
5454
}
5555

5656
fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
57-
let renderer = sub_args.value_of("renderer").expect("Required argument");
57+
let renderer = sub_args
58+
.get_one::<String>("renderer")
59+
.expect("Required argument");
5860
let supported = pre.supports_renderer(renderer);
5961

6062
// Signal whether the renderer is supported by exiting with 1 or 0.

src/book/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ impl MDBook {
313313
}
314314
}
315315

316+
debug!("running {:?}", cmd);
316317
let output = cmd.output()?;
317318

318319
if !output.status.success() {

src/cmd/build.rs

+9-21
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,30 @@
1+
use super::command_prelude::*;
12
use crate::{get_book_dir, open};
2-
use clap::{arg, App, Arg, ArgMatches};
33
use mdbook::errors::Result;
44
use mdbook::MDBook;
5+
use std::path::PathBuf;
56

67
// Create clap subcommand arguments
7-
pub fn make_subcommand<'help>() -> App<'help> {
8-
App::new("build")
8+
pub fn make_subcommand() -> Command {
9+
Command::new("build")
910
.about("Builds a book from its markdown files")
10-
.arg(
11-
Arg::new("dest-dir")
12-
.short('d')
13-
.long("dest-dir")
14-
.value_name("dest-dir")
15-
.help(
16-
"Output directory for the book{n}\
17-
Relative paths are interpreted relative to the book's root directory.{n}\
18-
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
19-
),
20-
)
21-
.arg(arg!([dir]
22-
"Root directory for the book{n}\
23-
(Defaults to the Current Directory when omitted)"
24-
))
25-
.arg(arg!(-o --open "Opens the compiled book in a web browser"))
11+
.arg_dest_dir()
12+
.arg_root_dir()
13+
.arg_open()
2614
}
2715

2816
// Build command implementation
2917
pub fn execute(args: &ArgMatches) -> Result<()> {
3018
let book_dir = get_book_dir(args);
3119
let mut book = MDBook::load(&book_dir)?;
3220

33-
if let Some(dest_dir) = args.value_of("dest-dir") {
21+
if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
3422
book.config.build.build_dir = dest_dir.into();
3523
}
3624

3725
book.build()?;
3826

39-
if args.is_present("open") {
27+
if args.get_flag("open") {
4028
// FIXME: What's the right behaviour if we don't use the HTML renderer?
4129
let path = book.build_dir_for("html").join("index.html");
4230
if !path.exists() {

src/cmd/clean.rs

+7-19
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,24 @@
1+
use super::command_prelude::*;
12
use crate::get_book_dir;
23
use anyhow::Context;
3-
use clap::{arg, App, Arg, ArgMatches};
44
use mdbook::MDBook;
55
use std::fs;
6+
use std::path::PathBuf;
67

78
// Create clap subcommand arguments
8-
pub fn make_subcommand<'help>() -> App<'help> {
9-
App::new("clean")
9+
pub fn make_subcommand() -> Command {
10+
Command::new("clean")
1011
.about("Deletes a built book")
11-
.arg(
12-
Arg::new("dest-dir")
13-
.short('d')
14-
.long("dest-dir")
15-
.value_name("dest-dir")
16-
.help(
17-
"Output directory for the book{n}\
18-
Relative paths are interpreted relative to the book's root directory.{n}\
19-
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
20-
),
21-
)
22-
.arg(arg!([dir]
23-
"Root directory for the book{n}\
24-
(Defaults to the Current Directory when omitted)"
25-
))
12+
.arg_dest_dir()
13+
.arg_root_dir()
2614
}
2715

2816
// Clean command implementation
2917
pub fn execute(args: &ArgMatches) -> mdbook::errors::Result<()> {
3018
let book_dir = get_book_dir(args);
3119
let book = MDBook::load(&book_dir)?;
3220

33-
let dir_to_remove = match args.value_of("dest-dir") {
21+
let dir_to_remove = match args.get_one::<PathBuf>("dest-dir") {
3422
Some(dest_dir) => dest_dir.into(),
3523
None => book.root.join(&book.config.build.build_dir),
3624
};

src/cmd/command_prelude.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//! Helpers for building the command-line arguments for commands.
2+
3+
pub use clap::{arg, Arg, ArgMatches, Command};
4+
use std::path::PathBuf;
5+
6+
pub trait CommandExt: Sized {
7+
fn _arg(self, arg: Arg) -> Self;
8+
9+
fn arg_dest_dir(self) -> Self {
10+
self._arg(
11+
Arg::new("dest-dir")
12+
.short('d')
13+
.long("dest-dir")
14+
.value_name("dest-dir")
15+
.value_parser(clap::value_parser!(PathBuf))
16+
.help(
17+
"Output directory for the book\n\
18+
Relative paths are interpreted relative to the book's root directory.\n\
19+
If omitted, mdBook uses build.build-dir from book.toml \
20+
or defaults to `./book`.",
21+
),
22+
)
23+
}
24+
25+
fn arg_root_dir(self) -> Self {
26+
self._arg(
27+
Arg::new("dir")
28+
.help(
29+
"Root directory for the book\n\
30+
(Defaults to the current directory when omitted)",
31+
)
32+
.value_parser(clap::value_parser!(PathBuf)),
33+
)
34+
}
35+
36+
fn arg_open(self) -> Self {
37+
self._arg(arg!(-o --open "Opens the compiled book in a web browser"))
38+
}
39+
}
40+
41+
impl CommandExt for Command {
42+
fn _arg(self, arg: Arg) -> Self {
43+
self.arg(arg)
44+
}
45+
}

src/cmd/init.rs

+18-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::get_book_dir;
2-
use clap::{arg, App, Arg, ArgMatches};
2+
use clap::{arg, ArgMatches, Command as ClapCommand};
33
use mdbook::config;
44
use mdbook::errors::Result;
55
use mdbook::MDBook;
@@ -8,30 +8,22 @@ use std::io::Write;
88
use std::process::Command;
99

1010
// Create clap subcommand arguments
11-
pub fn make_subcommand<'help>() -> App<'help> {
12-
App::new("init")
11+
pub fn make_subcommand() -> ClapCommand {
12+
ClapCommand::new("init")
1313
.about("Creates the boilerplate structure and files for a new book")
14-
// the {n} denotes a newline which will properly aligned in all help messages
15-
.arg(arg!([dir]
16-
"Directory to create the book in{n}\
17-
(Defaults to the Current Directory when omitted)"
18-
))
19-
.arg(arg!(--theme "Copies the default theme into your source folder"))
20-
.arg(arg!(--force "Skips confirmation prompts"))
2114
.arg(
22-
Arg::new("title")
23-
.long("title")
24-
.takes_value(true)
25-
.help("Sets the book title")
26-
.required(false),
15+
arg!([dir]
16+
"Directory to create the book in\n\
17+
(Defaults to the current directory when omitted)"
18+
)
19+
.value_parser(clap::value_parser!(std::path::PathBuf)),
2720
)
21+
.arg(arg!(--theme "Copies the default theme into your source folder"))
22+
.arg(arg!(--force "Skips confirmation prompts"))
23+
.arg(arg!(--title <title> "Sets the book title"))
2824
.arg(
29-
Arg::new("ignore")
30-
.long("ignore")
31-
.takes_value(true)
32-
.possible_values(&["none", "git"])
33-
.help("Creates a VCS ignore file (i.e. .gitignore)")
34-
.required(false),
25+
arg!(--ignore <ignore> "Creates a VCS ignore file (i.e. .gitignore)")
26+
.value_parser(["none", "git"]),
3527
)
3628
}
3729

@@ -41,12 +33,12 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
4133
let mut builder = MDBook::init(&book_dir);
4234
let mut config = config::Config::default();
4335
// If flag `--theme` is present, copy theme to src
44-
if args.is_present("theme") {
36+
if args.get_flag("theme") {
4537
let theme_dir = book_dir.join("theme");
4638
println!();
4739
println!("Copying the default theme to {}", theme_dir.display());
4840
// Skip this if `--force` is present
49-
if !args.is_present("force") && theme_dir.exists() {
41+
if !args.get_flag("force") && theme_dir.exists() {
5042
println!("This could potentially overwrite files already present in that directory.");
5143
print!("\nAre you sure you want to continue? (y/n) ");
5244

@@ -59,7 +51,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
5951
}
6052
}
6153

62-
if let Some(ignore) = args.value_of("ignore") {
54+
if let Some(ignore) = args.get_one::<String>("ignore").map(|s| s.as_str()) {
6355
match ignore {
6456
"git" => builder.create_gitignore(true),
6557
_ => builder.create_gitignore(false),
@@ -71,8 +63,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
7163
}
7264
}
7365

74-
config.book.title = if args.is_present("title") {
75-
args.value_of("title").map(String::from)
66+
config.book.title = if args.contains_id("title") {
67+
args.get_one::<String>("title").map(String::from)
7668
} else {
7769
request_book_title()
7870
};

src/cmd/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
pub mod build;
44
pub mod clean;
5+
pub mod command_prelude;
56
pub mod init;
67
#[cfg(feature = "serve")]
78
pub mod serve;

0 commit comments

Comments
 (0)