fix(cli): support loose boolean values for flags (#2721)

Allow boolean flags to accept 1/0, yes/no, on/off in addition to true/false using clap's BoolishValueParser.
This commit is contained in:
Luna Yao
2026-10-18 20:06:33 +08:00
committed by GitHub
parent f1b910da4e
commit 4ff27c7ef4
+48 -8
View File
@@ -19,13 +19,15 @@ use crate::{
};
use anyhow::Context;
use cidr::IpCidr;
use clap::{Arg, ArgMatches, CommandFactory, FromArgMatches, Parser};
use clap::{
Arg, ArgMatches, CommandFactory, FromArgMatches, Parser, builder::TypedValueParser as _,
};
use easytier_core::config::{DhcpConfig, EncryptionAlgorithm, normalize_secure_mode_config};
use guarden::defer;
use prost_types::field_descriptor_proto::Type;
use rust_i18n::t;
use serde_json::{Value, json};
use std::str::{FromStr, ParseBoolError};
use std::str::FromStr;
use std::{
net::{IpAddr, SocketAddr},
path::PathBuf,
@@ -1102,9 +1104,9 @@ fn cli_command() -> clap::Command {
value.parse::<T>().map(|value| json!(value))
}
fn negated(value: &str) -> Result<Value, ParseBoolError> {
value.parse::<bool>().map(|value| json!(!value))
}
let parser = clap::builder::BoolishValueParser::new();
let boolish = parser.map(|v| json!(v));
let negated = parser.map(|v| json!(!v));
Cli::command().args(Flags::flags().iter().map(|field| {
let name = field.name();
@@ -1115,11 +1117,11 @@ fn cli_command() -> clap::Command {
.short('u')
.num_args(0..=1)
.default_missing_value("true")
.value_parser(negated),
.value_parser(negated.clone()),
"enable_ipv6" => arg(name, "disable_ipv6")
.num_args(0..=1)
.default_missing_value("true")
.value_parser(negated),
.value_parser(negated.clone()),
// The command line names the algorithm instead of spelling the field.
// The values are the schema's own, which the patch reads.
"data_compress_algo" => {
@@ -1138,7 +1140,7 @@ fn cli_command() -> clap::Command {
Type::Bool => arg
.num_args(0..=1)
.default_missing_value("true")
.value_parser(parsed::<bool>),
.value_parser(boolish.clone()),
Type::Uint32 => arg.value_parser(parsed::<u32>),
Type::Uint64 => arg.value_parser(parsed::<u64>),
// An enum flag takes the name the schema spells, and the patch's
@@ -1772,6 +1774,44 @@ enabled = true
let patch = parse_flags(&["easytier", "--disable-ipv6"]).unwrap();
assert_eq!(patch.enable_ipv6, Some(false));
// Boolish tests: accepts 1/0, yes/no, on/off, true/false
assert_eq!(
parse_flags(&["easytier", "--latency-first", "1"])
.unwrap()
.latency_first,
Some(true)
);
assert_eq!(
parse_flags(&["easytier", "--latency-first", "0"])
.unwrap()
.latency_first,
Some(false)
);
assert_eq!(
parse_flags(&["easytier", "--latency-first", "yes"])
.unwrap()
.latency_first,
Some(true)
);
assert_eq!(
parse_flags(&["easytier", "--latency-first", "no"])
.unwrap()
.latency_first,
Some(false)
);
assert_eq!(
parse_flags(&["easytier", "--disable-encryption", "1"])
.unwrap()
.enable_encryption,
Some(false)
);
assert_eq!(
parse_flags(&["easytier", "--disable-encryption", "0"])
.unwrap()
.enable_encryption,
Some(true)
);
// Compression tests: case-insensitive, accepts None/none/zstd/Zstd/ZSTD, rejects invalid
let patch = parse_flags(&["easytier", "--compression", "none"]).unwrap();
assert_eq!(