summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Ickstadt <mattico8@gmail.com>2018-08-02 15:48:22 -0500
committerMatt Ickstadt <mattico8@gmail.com>2018-08-02 16:52:41 -0500
commitb8f8e768998dbca1fb29ee09f8a1f737297556d3 (patch)
tree64383280abfb7564d78016ce9b8b1af531225fb3
parentac4e00c7c6bf388fffc2c8126f9f8c10008e6aeb (diff)
Improve command-line argument parsing
-rw-r--r--src/cmd/build.rs14
-rw-r--r--src/cmd/clean.rs13
-rw-r--r--src/cmd/init.rs8
-rw-r--r--src/cmd/serve.rs73
-rw-r--r--src/cmd/test.rs25
-rw-r--r--src/cmd/watch.rs11
-rw-r--r--src/main.rs29
7 files changed, 115 insertions, 58 deletions
diff --git a/src/cmd/build.rs b/src/cmd/build.rs
index 7887c06c..350a3ece 100644
--- a/src/cmd/build.rs
+++ b/src/cmd/build.rs
@@ -1,21 +1,21 @@
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::Result;
use mdbook::MDBook;
-use std::path::PathBuf;
use {get_book_dir, open};
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("build")
- .about("Build the book from the markdown files")
- .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
+ .about("Builds a book from its markdown files")
.arg_from_usage(
- "-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book \
- when omitted)'",
+ "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
+ (If omitted, uses build.build-dir from book.toml or defaults to ./book)'",
)
.arg_from_usage(
- "[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
+ "[dir] 'Root directory for the book{n}\
+ (Defaults to the Current Directory when omitted)'",
)
+ .arg_from_usage("-o, --open 'Opens the compiled book in a web browser'")
}
// Build command implementation
@@ -24,7 +24,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
let mut book = MDBook::load(&book_dir)?;
if let Some(dest_dir) = args.value_of("dest-dir") {
- book.config.build.build_dir = PathBuf::from(dest_dir);
+ book.config.build.build_dir = dest_dir.into();
}
book.build()?;
diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs
index 92b69566..9bcf3f20 100644
--- a/src/cmd/clean.rs
+++ b/src/cmd/clean.rs
@@ -3,15 +3,18 @@ use get_book_dir;
use mdbook::errors::*;
use mdbook::MDBook;
use std::fs;
-use std::path::PathBuf;
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("clean")
- .about("Delete built book")
+ .about("Deletes a built book")
.arg_from_usage(
- "-d, --dest-dir=[dest-dir] 'The directory of built book{n}(Defaults to ./book when \
- omitted)'",
+ "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
+ (If omitted, uses build.build-dir from book.toml or defaults to ./book)'",
+ )
+ .arg_from_usage(
+ "[dir] 'Root directory for the book{n}\
+ (Defaults to the Current Directory when omitted)'",
)
}
@@ -21,7 +24,7 @@ pub fn execute(args: &ArgMatches) -> ::mdbook::errors::Result<()> {
let book = MDBook::load(&book_dir)?;
let dir_to_remove = match args.value_of("dest-dir") {
- Some(dest_dir) => PathBuf::from(dest_dir),
+ Some(dest_dir) => dest_dir.into(),
None => book.root.join(&book.config.build.build_dir),
};
fs::remove_dir_all(&dir_to_remove).chain_err(|| "Unable to remove the build directory")?;
diff --git a/src/cmd/init.rs b/src/cmd/init.rs
index 134eda80..629563b2 100644
--- a/src/cmd/init.rs
+++ b/src/cmd/init.rs
@@ -10,12 +10,12 @@ use std::process::Command;
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("init")
- .about("Create boilerplate structure and files in the directory")
+ .about("Creates the boilerplate structure and files for a new book")
// the {n} denotes a newline which will properly aligned in all help messages
- .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory \
- when omitted)'")
+ .arg_from_usage("[dir] 'Directory to create the book in{n}\
+ (Defaults to the Current Directory when omitted)'")
.arg_from_usage("--theme 'Copies the default theme into your source folder'")
- .arg_from_usage("--force 'skip confirmation prompts'")
+ .arg_from_usage("--force 'Skips confirmation prompts'")
}
// Init command implementation
diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs
index 22aa3ab9..421c37e1 100644
--- a/src/cmd/serve.rs
+++ b/src/cmd/serve.rs
@@ -7,7 +7,7 @@ use self::iron::{
};
#[cfg(feature = "watch")]
use super::watch;
-use clap::{App, ArgMatches, SubCommand};
+use clap::{App, Arg, ArgMatches, SubCommand};
use mdbook::errors::*;
use mdbook::utils;
use mdbook::MDBook;
@@ -19,23 +19,52 @@ struct ErrorRecover;
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("serve")
- .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
+ .about("Serves a book at http://localhost:3000, and rebuilds it on changes")
.arg_from_usage(
- "[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
+ "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
+ (If omitted, uses build.build-dir from book.toml or defaults to ./book)'",
)
- .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
.arg_from_usage(
- "-w, --websocket-port=[ws-port] 'Use another port for the websocket connection \
- (livereload){n}(Defaults to 3001)'",
+ "[dir] 'Root directory for the book{n}\
+ (Defaults to the Current Directory when omitted)'",
)
- .arg_from_usage(
- "-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'",
+ .arg(
+ Arg::with_name("hostname")
+ .short("n")
+ .long("hostname")
+ .takes_value(true)
+ .default_value("localhost")
+ .empty_values(false)
+ .help("Hostname to listen on for HTTP connections"),
)
- .arg_from_usage(
- "-a, --address=[address] 'Address that the browser can reach the websocket server \
- from{n}(Defaults to the interface address)'",
+ .arg(
+ Arg::with_name("port")
+ .short("p")
+ .long("port")
+ .takes_value(true)
+ .default_value("3000")
+ .empty_values(false)
+ .help("Port to use for HTTP connections"),
+ )
+ .arg(
+ Arg::with_name("websocket-hostname")
+ .long("websocket-hostname")
+ .takes_value(true)
+ .empty_values(false)
+ .help(
+ "Hostname to connect to for WebSockets connections (Defaults to the HTTP hostname)",
+ ),
+ )
+ .arg(
+ Arg::with_name("websocket-port")
+ .short("w")
+ .long("websocket-port")
+ .takes_value(true)
+ .default_value("3001")
+ .empty_values(false)
+ .help("Port to use for WebSockets livereload connections"),
)
- .arg_from_usage("-o, --open 'Open the book server in a web browser'")
+ .arg_from_usage("-o, --open 'Opens the book server in a web browser'")
}
// Watch command implementation
@@ -43,19 +72,23 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
- let port = args.value_of("port").unwrap_or("3000");
- let ws_port = args.value_of("websocket-port").unwrap_or("3001");
- let interface = args.value_of("interface").unwrap_or("localhost");
- let public_address = args.value_of("address").unwrap_or(interface);
+ let port = args.value_of("port").unwrap();
+ let ws_port = args.value_of("websocket-port").unwrap();
+ let hostname = args.value_of("hostname").unwrap();
+ let public_address = args.value_of("websocket-address").unwrap_or(hostname);
let open_browser = args.is_present("open");
- let address = format!("{}:{}", interface, port);
- let ws_address = format!("{}:{}", interface, ws_port);
+ let address = format!("{}:{}", hostname, port);
+ let ws_address = format!("{}:{}", hostname, ws_port);
let livereload_url = format!("ws://{}:{}", public_address, ws_port);
book.config
.set("output.html.livereload-url", &livereload_url)?;
+ if let Some(dest_dir) = args.value_of("dest-dir") {
+ book.config.build.build_dir = dest_dir.into();
+ }
+
book.build()?;
let mut chain = Chain::new(staticfile::Static::new(book.build_dir_for("html")));
@@ -87,10 +120,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
// FIXME: This area is really ugly because we need to re-set livereload :(
- let livereload_url = livereload_url.clone();
-
let result = MDBook::load(&book_dir)
- .and_then(move |mut b| {
+ .and_then(|mut b| {
b.config.set("output.html.livereload-url", &livereload_url)?;
Ok(b)
})
diff --git a/src/cmd/test.rs b/src/cmd/test.rs
index 8409590a..dac841c6 100644
--- a/src/cmd/test.rs
+++ b/src/cmd/test.rs
@@ -1,4 +1,4 @@
-use clap::{App, ArgMatches, SubCommand};
+use clap::{App, Arg, ArgMatches, SubCommand};
use get_book_dir;
use mdbook::errors::Result;
use mdbook::MDBook;
@@ -6,11 +6,24 @@ use mdbook::MDBook;
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("test")
- .about("Test that code samples compile")
- .arg_from_usage("-L, --library-path [DIR]... 'directories to add to crate search path'")
+ .about("Tests that a book's Rust code samples compile")
.arg_from_usage(
- "[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
+ "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
+ (If omitted, uses build.build-dir from book.toml or defaults to ./book)'",
)
+ .arg_from_usage(
+ "[dir] 'Root directory for the book{n}\
+ (Defaults to the Current Directory when omitted)'",
+ )
+ .arg(Arg::with_name("library-path")
+ .short("L")
+ .long("library-path")
+ .value_name("dir")
+ .takes_value(true)
+ .require_delimiter(true)
+ .multiple(true)
+ .empty_values(false)
+ .help("A comma-separated list of directories to add to {n}the crate search path when building tests"))
}
// test command implementation
@@ -21,6 +34,10 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
+ if let Some(dest_dir) = args.value_of("dest-dir") {
+ book.config.build.build_dir = dest_dir.into();
+ }
+
book.test(library_paths)?;
Ok(())
diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs
index e5848970..0f809251 100644
--- a/src/cmd/watch.rs
+++ b/src/cmd/watch.rs
@@ -13,11 +13,16 @@ use {get_book_dir, open};
// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("watch")
- .about("Watch the files for changes")
- .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
+ .about("Watches a book's files and rebuilds it on changes")
+ .arg_from_usage(
+ "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
+ (If omitted, uses build.build-dir from book.toml or defaults to ./book)'",
+ )
.arg_from_usage(
- "[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
+ "[dir] 'Root directory for the book{n}\
+ (Defaults to the Current Directory when omitted)'",
)
+ .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
}
// Watch command implementation
diff --git a/src/main.rs b/src/main.rs
index 8a1a2e9b..86147532 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,26 +20,27 @@ use std::path::{Path, PathBuf};
mod cmd;
-const NAME: &'static str = "mdbook";
+const NAME: &'static str = "mdBook";
+const VERSION: &'static str = concat!("v", crate_version!());
fn main() {
init_logger();
// Create a list of valid arguments and sub-commands
let app = App::new(NAME)
- .about("Create a book in form of a static website from markdown files")
- .author("Mathieu David <mathieudavid@mathieudavid.org>")
- // Get the version from our Cargo.toml using clap's crate_version!() macro
- .version(concat!("v",crate_version!()))
- .setting(AppSettings::ArgRequiredElseHelp)
- .after_help("For more information about a specific command, \
- try `mdbook <command> --help`\n\
- Source code for mdbook available \
- at: https://github.com/rust-lang-nursery/mdBook")
- .subcommand(cmd::init::make_subcommand())
- .subcommand(cmd::build::make_subcommand())
- .subcommand(cmd::test::make_subcommand())
- .subcommand(cmd::clean::make_subcommand());
+ .about("Creates a book from markdown files")
+ .author("Mathieu David <mathieudavid@mathieudavid.org>")
+ .version(VERSION)
+ .setting(AppSettings::GlobalVersion)
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .after_help(
+ "For more information about a specific command, try `mdbook <command> --help`\n\
+ The source code for mdBook is available at: https://github.com/rust-lang-nursery/mdBook",
+ )
+ .subcommand(cmd::init::make_subcommand())
+ .subcommand(cmd::build::make_subcommand())
+ .subcommand(cmd::test::make_subcommand())
+ .subcommand(cmd::clean::make_subcommand());
#[cfg(feature = "watch")]
let app = app.subcommand(cmd::watch::make_subcommand());