From 3c866c32ec9135731d29066a980ca4edb692201d Mon Sep 17 00:00:00 2001 From: Fabio Valentini Date: Mon, 30 Sep 2024 14:55:09 +0200 Subject: [PATCH] backport support for clap v4 --- src/bindgen/builder.rs | 2 +- src/bindgen/cargo/cargo.rs | 2 +- src/main.rs | 120 ++++++++++++++++++++----------------- tests/depfile.rs | 12 +++- 4 files changed, 76 insertions(+), 60 deletions(-) diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index a0328b4..4d2eee1 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -375,7 +375,7 @@ impl Builder { } if let Some((lib_dir, binding_lib_name)) = self.lib.clone() { - let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str()); + let lockfile = self.lockfile.as_deref(); let cargo = Cargo::load( &lib_dir, diff --git a/src/bindgen/cargo/cargo.rs b/src/bindgen/cargo/cargo.rs index 69cf938..542f8e3 100644 --- a/src/bindgen/cargo/cargo.rs +++ b/src/bindgen/cargo/cargo.rs @@ -36,7 +36,7 @@ impl Cargo { /// need to be parsed. pub(crate) fn load( crate_dir: &Path, - lock_file: Option<&str>, + lock_file: Option<&Path>, binding_crate_name: Option<&str>, use_cargo_lock: bool, clean: bool, diff --git a/src/main.rs b/src/main.rs index eb78a08..cd4f271 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,60 +20,58 @@ extern crate quote; extern crate syn; extern crate toml; -use clap::{Arg, ArgMatches, Command}; +use clap::{value_parser, Arg, ArgAction, ArgMatches, Command}; mod bindgen; mod logging; -use crate::bindgen::{Bindings, Builder, Cargo, Config, Error, Profile, Style}; +use bindgen::{Bindings, Builder, Cargo, Config, Error}; fn apply_config_overrides(config: &mut Config, matches: &ArgMatches) { // We allow specifying a language to override the config default. This is // used by compile-tests. - if let Some(lang) = matches.value_of("lang") { - config.language = match lang.parse() { - Ok(lang) => lang, - Err(reason) => { - error!("{}", reason); - return; - } + match matches.try_get_one::("lang") { + Ok(Some(lang)) => { + config.language = bindgen::Language::from_str(lang).unwrap(); + } + Err(reason) => { + error!("{}", reason); + return; } + _ => (), } - if matches.is_present("cpp-compat") { + if matches.get_flag("cpp-compat") { config.cpp_compat = true; } - if matches.is_present("only-target-dependencies") { + if matches.get_flag("only-target-dependencies") { config.only_target_dependencies = true; } - if let Some(style) = matches.value_of("style") { - config.style = match style { - "Both" => Style::Both, - "both" => Style::Both, - "Tag" => Style::Tag, - "tag" => Style::Tag, - "Type" => Style::Type, - "type" => Style::Type, - _ => { - error!("Unknown style specified."); - return; - } + match matches.try_get_one::("style") { + Ok(Some(style)) => { + config.style = bindgen::Style::from_str(style).unwrap(); + } + Err(_) => { + error!("Unknown style specified."); + return; } + _ => (), } - if let Some(profile) = matches.value_of("profile") { - config.parse.expand.profile = match Profile::from_str(profile) { - Ok(p) => p, - Err(e) => { - error!("{}", e); - return; - } + match matches.try_get_one::("profile") { + Ok(Some(profile)) => { + config.parse.expand.profile = bindgen::Profile::from_str(profile).unwrap(); + } + Err(e) => { + error!("{}", e); + return; } + _ => (), } - if matches.is_present("d") { + if matches.get_flag("d") { config.parse.parse_deps = true; } } @@ -82,7 +80,7 @@ fn load_bindings(input: &Path, matches: &ArgMatches) -> Result // If a file is specified then we load it as a single source if !input.is_dir() { // Load any config specified or search in the input directory - let mut config = match matches.value_of("config") { + let mut config = match matches.get_one::("config") { Some(c) => Config::from_file(c).unwrap(), None => Config::from_root_or_default( input @@ -102,16 +100,16 @@ fn load_bindings(input: &Path, matches: &ArgMatches) -> Result // We have to load a whole crate, so we use cargo to gather metadata let lib = Cargo::load( input, - matches.value_of("lockfile"), - matches.value_of("crate"), + matches.get_one::("lockfile").map(|s| s.as_path()), + matches.get_one::("crate").map(|s| s.as_str()), true, - matches.is_present("clean"), - matches.is_present("only-target-dependencies"), - matches.value_of("metadata").map(Path::new), + matches.get_flag("clean"), + matches.get_flag("only-target-dependencies"), + matches.get_one::("metadata").map(Path::new), )?; // Load any config specified or search in the binding crate directory - let mut config = match matches.value_of("config") { + let mut config = match matches.get_one::("config") { Some(c) => Config::from_file(c).unwrap(), None => { let binding_crate_dir = lib.find_crate_dir(&lib.binding_crate_ref()); @@ -140,12 +138,13 @@ fn main() { .arg( Arg::new("v") .short('v') - .multiple_occurrences(true) + .action(ArgAction::Count) .help("Enable verbose logging"), ) .arg( Arg::new("verify") .long("verify") + .action(ArgAction::SetTrue) .help("Generate bindings and compare it to the existing bindings file and error if they are different"), ) .arg( @@ -153,6 +152,7 @@ fn main() { .short('c') .long("config") .value_name("PATH") + .value_parser(value_parser!(PathBuf)) .help("Specify path to a `cbindgen.toml` config to use"), ) .arg( @@ -161,16 +161,18 @@ fn main() { .long("lang") .value_name("LANGUAGE") .help("Specify the language to output bindings in") - .possible_values(["c++", "C++", "c", "C", "cython", "Cython"]), + .value_parser(["c++", "C++", "c", "C", "cython", "Cython"]), ) .arg( Arg::new("cpp-compat") .long("cpp-compat") + .action(ArgAction::SetTrue) .help("Whether to add C++ compatibility to generated C bindings") ) .arg( Arg::new("only-target-dependencies") .long("only-target-dependencies") + .action(ArgAction::SetTrue) .help("Only fetch dependencies needed by the target platform. \ The target platform defaults to the host platform; set TARGET to override.") ) @@ -180,17 +182,19 @@ fn main() { .long("style") .value_name("STYLE") .help("Specify the declaration style to use for bindings") - .possible_values(["Both", "both", "Tag", "tag", "Type", "type"]), + .value_parser(["Both", "both", "Tag", "tag", "Type", "type"]), ) .arg( Arg::new("d") .short('d') .long("parse-dependencies") + .action(ArgAction::SetTrue) .help("Whether to parse dependencies when generating bindings"), ) .arg( Arg::new("clean") .long("clean") + .action(ArgAction::SetTrue) .help( "Whether to use a new temporary directory for expanding macros. \ Affects performance, but might be required in certain build processes.") @@ -203,6 +207,7 @@ fn main() { In general this is the folder where the Cargo.toml file of \ source Rust library resides.") .required(false) + .value_parser(value_parser!(PathBuf)) .index(1), ) .arg( @@ -221,6 +226,7 @@ fn main() { .long("output") .value_name("PATH") .help("The file to output the bindings to") + .value_parser(value_parser!(PathBuf)) .required(false), ) .arg( @@ -232,6 +238,7 @@ fn main() { is not specified, the Cargo.lock file is searched for in the \ same folder as the Cargo.toml file. This option is useful for \ projects that use workspaces.") + .value_parser(value_parser!(PathBuf)) .required(false), ) .arg( @@ -247,6 +254,7 @@ fn main() { `cargo metadata --all-features --format-version 1 \ --manifest-path " ) + .value_parser(value_parser!(PathBuf)) .required(false), ) .arg( @@ -257,12 +265,13 @@ fn main() { "Specify the profile to use when expanding macros. \ Has no effect otherwise." ) - .possible_values(["Debug", "debug", "Release", "release"]), + .value_parser(["Debug", "debug", "Release", "release"]), ) .arg( Arg::new("quiet") .short('q') .long("quiet") + .action(ArgAction::SetTrue) .help("Report errors only (overrides verbosity options).") .required(false), ) @@ -270,10 +279,9 @@ fn main() { Arg::new("depfile") .value_name("PATH") .long("depfile") - .takes_value(true) - .min_values(1) - .max_values(1) + .num_args(1) .required(false) + .value_parser(value_parser!(PathBuf)) .help("Generate a depfile at the given Path listing the source files \ cbindgen traversed when generating the bindings. Useful when \ integrating cbindgen into 3rd party build-systems. \ @@ -282,7 +290,7 @@ fn main() { ) .get_matches(); - if !matches.is_present("out") && matches.is_present("verify") { + if matches.get_flag("verify") && !matches.contains_id("out") { error!( "Cannot verify bindings against `stdout`, please specify a file to compare against." ); @@ -290,10 +298,10 @@ fn main() { } // Initialize logging - if matches.is_present("quiet") { + if matches.get_flag("quiet") { logging::ErrorLogger::init().unwrap(); } else { - match matches.occurrences_of("v") { + match matches.get_count("v") { 0 => logging::WarnLogger::init().unwrap(), 1 => logging::InfoLogger::init().unwrap(), _ => logging::TraceLogger::init().unwrap(), @@ -301,10 +309,10 @@ fn main() { } // Find the input directory - let input = match matches.value_of("INPUT") { - Some(input) => PathBuf::from(input), - None => env::current_dir().unwrap(), - }; + let input: PathBuf = matches + .get_one("INPUT") + .cloned() + .unwrap_or_else(|| env::current_dir().unwrap()); let bindings = match load_bindings(&input, &matches) { Ok(bindings) => bindings, @@ -316,15 +324,15 @@ fn main() { }; // Write the bindings file - match matches.value_of("out") { + match matches.get_one::("out") { Some(file) => { let changed = bindings.write_to_file(file); - if matches.is_present("verify") && changed { - error!("Bindings changed: {}", file); + if matches.get_flag("verify") && changed { + error!("Bindings changed: {}", file.display()); std::process::exit(2); } - if let Some(depfile) = matches.value_of("depfile") { + if let Some(depfile) = matches.get_one("depfile") { bindings.generate_depfile(file, depfile) } } diff --git a/tests/depfile.rs b/tests/depfile.rs index 7d629f3..512f69b 100644 --- a/tests/depfile.rs +++ b/tests/depfile.rs @@ -44,7 +44,11 @@ fn test_project(project_path: &str) { let mut cmake_build = Command::new("cmake"); cmake_build.arg("--build").arg(&build_dir); let output = cmake_build.output().expect("Failed to execute process"); - assert!(output.status.success(), "Building test project failed"); + assert!( + output.status.success(), + "Building test project failed: {:?}", + output + ); let out_str = String::from_utf8(output.stdout).unwrap(); assert!( out_str.contains("Running cbindgen"), @@ -85,7 +89,11 @@ fn test_project(project_path: &str) { assert_eq!(dep_list, expected_dep_list); let output = cmake_build.output().expect("Failed to execute process"); - assert!(output.status.success(), "Building test project failed"); + assert!( + output.status.success(), + "Building test project failed: {:?}", + output + ); let out_str = String::from_utf8(output.stdout).unwrap(); assert!( !out_str.contains("Running cbindgen"), -- 2.46.2