Update arg parsing to clap v3 (#1717)

* Update arg parsing to clap v3
This commit is contained in:
Marcin Puc 2022-01-23 20:21:41 +01:00 committed by Vincent Prouillet
parent 502dd92cc6
commit 0f23a40e3f
5 changed files with 223 additions and 185 deletions

93
Cargo.lock generated
View File

@ -291,12 +291,51 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"strsim 0.8.0",
"textwrap 0.11.0",
"unicode-width",
"vec_map",
]
[[package]]
name = "clap"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
]
[[package]]
name = "clap_complete"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e3cb395a9ef3c4ddabee9d6a0d0419b107cccf3e431fc0015df90f24849386c"
dependencies = [
"clap 3.0.0",
]
[[package]]
name = "clap_derive"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@ -1350,7 +1389,7 @@ dependencies = [
"anyhow",
"bincode",
"byteorder",
"clap",
"clap 2.34.0",
"encoding",
"glob",
"lindera-core",
@ -1892,6 +1931,15 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -2120,6 +2168,30 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
@ -2754,6 +2826,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strum"
version = "0.21.0"
@ -2933,6 +3011,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "thiserror"
version = "1.0.30"
@ -3590,7 +3674,8 @@ version = "0.16.0"
dependencies = [
"atty",
"chrono",
"clap",
"clap 3.0.0",
"clap_complete",
"ctrlc",
"errors",
"front_matter",

View File

@ -13,14 +13,15 @@ keywords = ["static", "site", "generator", "blog"]
include = ["src/**/*", "LICENSE", "README.md"]
[build-dependencies]
clap = "2"
clap = "3"
clap_complete = "3"
[[bin]]
name = "zola"
[dependencies]
atty = "0.2.11"
clap = { version = "2", default-features = false }
clap = { version = "3", features = ["derive"] }
chrono = "0.4"
lazy_static = "1.1"
termcolor = "1.0.4"

View File

@ -21,7 +21,7 @@ stages:
rustup_toolchain: stable
linux-pinned:
imageName: 'ubuntu-20.04'
rustup_toolchain: 1.53.0
rustup_toolchain: 1.54.0
pool:
vmImage: $(imageName)
steps:

View File

@ -1,102 +1,86 @@
use clap::{crate_authors, crate_description, crate_version, App, AppSettings, Arg, SubCommand};
use std::path::PathBuf;
pub fn build_cli() -> App<'static, 'static> {
App::new("zola")
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
.setting(AppSettings::SubcommandRequiredElseHelp)
.arg(
Arg::with_name("root")
.short("r")
.long("root")
.takes_value(true)
.default_value(".")
.help("Directory to use as root of project")
)
.arg(
Arg::with_name("config")
.short("c")
.long("config")
.takes_value(true)
.help("Path to a config file other than config.toml in the root of project")
)
.subcommands(vec![
SubCommand::with_name("init")
.about("Create a new Zola project")
.args(&[
Arg::with_name("name")
.default_value(".")
.help("Name of the project. Will create a new directory with that name in the current directory"),
Arg::with_name("force")
.short("f")
.long("force")
.takes_value(false)
.help("Force creation of project even if directory is non-empty")
]),
SubCommand::with_name("build")
.about("Deletes the output directory if there is one and builds the site")
.args(&[
Arg::with_name("base_url")
.short("u")
.long("base-url")
.takes_value(true)
.help("Force the base URL to be that value (default to the one in config.toml)"),
Arg::with_name("output_dir")
.short("o")
.long("output-dir")
.takes_value(true)
.help("Outputs the generated site in the given path (by default 'public' dir in project root)"),
Arg::with_name("drafts")
.long("drafts")
.takes_value(false)
.help("Include drafts when loading the site"),
]),
SubCommand::with_name("serve")
.about("Serve the site. Rebuild and reload on change automatically")
.args(&[
Arg::with_name("interface")
.short("i")
.long("interface")
.takes_value(true)
.help("Interface to bind on (default: 127.0.0.1)"),
Arg::with_name("port")
.short("p")
.long("port")
.takes_value(true)
.help("Which port to use (default: 1111)"),
Arg::with_name("output_dir")
.short("o")
.long("output-dir")
.takes_value(true)
.help("Outputs assets of the generated site in the given path (by default 'public' dir in project root). HTML/XML will be stored in memory."),
Arg::with_name("base_url")
.short("u")
.long("base-url")
.takes_value(true)
.help("Changes the base_url (default: 127.0.0.1)"),
Arg::with_name("drafts")
.long("drafts")
.takes_value(false)
.help("Include drafts when loading the site"),
Arg::with_name("open")
.short("O")
.long("open")
.takes_value(false)
.help("Open site in the default browser"),
Arg::with_name("fast")
.short("f")
.long("fast")
.takes_value(false)
.help("Only rebuild the minimum on change - useful when working on a specific page/section"),
]),
SubCommand::with_name("check")
.about("Try building the project without rendering it. Checks links")
.args(&[
Arg::with_name("drafts")
.long("drafts")
.takes_value(false)
.help("Include drafts when loading the site"),
])
])
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[clap(version, author, about)]
pub struct Cli {
/// Directory to use as root of project
#[clap(short = 'r', long, default_value = ".")]
pub root: PathBuf,
/// Path to a config file other than config.toml in the root of project
#[clap(short = 'c', long)]
pub config: Option<PathBuf>,
#[clap(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
/// Create a new Zola project
Init {
/// Name of the project. Will create a new directory with that name in the current directory
#[clap(default_value = ".")]
name: String,
/// Force creation of project even if directory is non-empty
#[clap(short = 'f', long)]
force: bool,
},
/// Deletes the output directory if there is one and builds the site
Build {
/// Force the base URL to be that value (defaults to the one in config.toml)
#[clap(short = 'u', long)]
base_url: Option<String>,
/// Outputs the generated site in the given path (by default 'public' dir in project root)
#[clap(short = 'o', long)]
output_dir: Option<PathBuf>,
/// Include drafts when loading the site
#[clap(long)]
drafts: bool,
},
/// Serve the site. Rebuild and reload on change automatically
Serve {
/// Interface to bind on
#[clap(short = 'i', long, default_value = "127.0.0.1")]
interface: String,
/// Which port to use
#[clap(short = 'p', long, default_value_t = 1111)]
port: u16,
/// Outputs assets of the generated site in the given path (by default 'public' dir in project root).
/// HTML/XML will be stored in memory.
#[clap(short = 'o', long)]
output_dir: Option<PathBuf>,
/// Changes the base_url
#[clap(short = 'u', long, default_value = "127.0.0.1")]
base_url: String,
/// Include drafts when loading the site
#[clap(long)]
drafts: bool,
/// Open site in the default browser
#[clap(short = 'O', long)]
open: bool,
/// Only rebuild the minimum on change - useful when working on a specific page/section
#[clap(short = 'f', long)]
fast: bool,
},
/// Try to build the project without rendering it. Checks links
Check {
/// Include drafts when loading the site
#[clap(long)]
drafts: bool,
},
}

View File

@ -1,124 +1,92 @@
use std::env;
use std::path::{Path, PathBuf};
use std::time::Instant;
use cli::{Cli, Command};
use utils::net::{get_available_port, port_is_available};
use clap::Parser;
mod cli;
mod cmd;
mod console;
mod prompt;
fn main() {
let matches = cli::build_cli().get_matches();
let cli = Cli::parse();
let root_dir = cli
.root
.canonicalize()
.unwrap_or_else(|_| panic!("Cannot find root directory: {}", cli.root.display()));
let config_file = cli
.config
.map(|path| {
path.canonicalize()
.unwrap_or_else(|_| panic!("Cannot find config file: {}", path.display()))
})
.unwrap_or_else(|| root_dir.join("config.toml"));
let root_dir = match matches.value_of("root").unwrap() {
"." => env::current_dir().unwrap(),
path => PathBuf::from(path)
.canonicalize()
.unwrap_or_else(|_| panic!("Cannot find root directory: {}", path)),
};
let config_file = match matches.value_of("config") {
Some(path) => PathBuf::from(path)
.canonicalize()
.unwrap_or_else(|_| panic!("Cannot find config file: {}", path)),
None => root_dir.join("config.toml"),
};
match matches.subcommand() {
("init", Some(matches)) => {
let force = matches.is_present("force");
match cmd::create_new_project(matches.value_of("name").unwrap(), force) {
Ok(()) => (),
Err(e) => {
console::unravel_errors("Failed to create the project", &e);
::std::process::exit(1);
}
};
match cli.command {
Command::Init { name, force } => {
if let Err(e) = cmd::create_new_project(&name, force) {
console::unravel_errors("Failed to create the proejct", &e);
std::process::exit(1);
}
}
("build", Some(matches)) => {
Command::Build { base_url, output_dir, drafts } => {
console::info("Building site...");
let start = Instant::now();
let output_dir = matches.value_of("output_dir").map(|output_dir| Path::new(output_dir));
match cmd::build(
&root_dir,
&config_file,
matches.value_of("base_url"),
output_dir,
matches.is_present("drafts"),
base_url.as_deref(),
output_dir.as_deref(),
drafts,
) {
Ok(()) => console::report_elapsed_time(start),
Err(e) => {
console::unravel_errors("Failed to build the site", &e);
::std::process::exit(1);
std::process::exit(1);
}
};
}
}
("serve", Some(matches)) => {
let interface = matches.value_of("interface").unwrap_or("127.0.0.1");
let mut port: u16 = match matches.value_of("port").unwrap_or("1111").parse() {
Ok(x) => x,
Err(_) => {
console::error("The request port needs to be an integer");
::std::process::exit(1);
}
};
let open = matches.is_present("open");
let include_drafts = matches.is_present("drafts");
let fast = matches.is_present("fast");
// Default one
Command::Serve { interface, mut port, output_dir, base_url, drafts, open, fast } => {
if port != 1111 && !port_is_available(port) {
console::error("The requested port is not available");
::std::process::exit(1);
std::process::exit(1);
}
if !port_is_available(port) {
port = if let Some(p) = get_available_port(1111) {
p
} else {
console::error("No port available.");
::std::process::exit(1);
}
port = get_available_port(1111).unwrap_or_else(|| {
console::error("No port available");
std::process::exit(1);
});
}
let output_dir = matches.value_of("output_dir").map(|output_dir| Path::new(output_dir));
let base_url = matches.value_of("base_url").unwrap_or("127.0.0.1");
console::info("Building site...");
match cmd::serve(
if let Err(e) = cmd::serve(
&root_dir,
interface,
&interface,
port,
output_dir,
base_url,
output_dir.as_deref(),
&base_url,
&config_file,
open,
include_drafts,
drafts,
fast,
) {
Ok(()) => (),
Err(e) => {
console::unravel_errors("", &e);
::std::process::exit(1);
}
};
console::unravel_errors("Failed to serve the site", &e);
std::process::exit(1);
}
}
("check", Some(matches)) => {
Command::Check { drafts } => {
console::info("Checking site...");
let start = Instant::now();
match cmd::check(
&root_dir,
&config_file,
matches.value_of("base_path"),
matches.value_of("base_url"),
matches.is_present("drafts"),
) {
match cmd::check(&root_dir, &config_file, None, None, drafts) {
Ok(()) => console::report_elapsed_time(start),
Err(e) => {
console::unravel_errors("Failed to check the site", &e);
::std::process::exit(1);
std::process::exit(1);
}
};
}
}
_ => unreachable!(),
}
}