Browse Source

feat: accept Go-style single-dash CLI options

Go's flag package uses single dash (-port) while clap uses double dash
(--port). Add normalize_args_vec() to convert single-dash long options
to double-dash before clap parsing, so both formats work. Update test
framework to use single-dash flags matching Go convention.
rust-volume-server
Chris Lu 1 day ago
parent
commit
12174d62b3
  1. 88
      seaweed-volume/src/config.rs
  2. 28
      test/volume_server/framework/cluster_rust.go

88
seaweed-volume/src/config.rs

@ -252,9 +252,47 @@ pub enum MinFreeSpace {
Bytes(u64),
}
/// Convert single-dash long options to double-dash for clap compatibility.
/// Go's `flag` package uses `-port`, clap expects `--port`.
/// This allows both `-port 8080` and `--port 8080` to work.
fn normalize_args_vec(args: Vec<String>) -> Vec<String> {
let mut args = args;
// Skip args[0] (binary name).
let mut i = 1;
while i < args.len() {
let arg = &args[i];
// Stop processing after "--"
if arg == "--" {
break;
}
// Already double-dash or not a flag: leave as-is
if arg.starts_with("--") || !arg.starts_with('-') {
i += 1;
continue;
}
// Single char flags like -h, -V: leave as-is
let without_dash = &arg[1..];
// Check if it's a single-dash long option: more than 1 char and not a negative number
if without_dash.len() > 1 && !without_dash.starts_with(|c: char| c.is_ascii_digit()) {
// Handle -key=value format
if let Some(eq_pos) = without_dash.find('=') {
let key = &without_dash[..eq_pos];
if key.len() > 1 {
args[i] = format!("--{}", without_dash);
}
} else {
args[i] = format!("-{}", arg);
}
}
i += 1;
}
args
}
/// Parse CLI arguments and resolve all defaults — mirroring Go's `runVolume()` + `startVolumeServer()`.
pub fn parse_cli() -> VolumeServerConfig {
let cli = Cli::parse();
let args: Vec<String> = std::env::args().collect();
let cli = Cli::parse_from(normalize_args_vec(args));
resolve_config(cli)
}
@ -823,6 +861,54 @@ mod tests {
assert_eq!(tags[1], Vec::<String>::new());
}
#[test]
fn test_normalize_args_single_dash_to_double() {
let args = vec![
"bin".into(),
"-port".into(), "8080".into(),
"-ip.bind".into(), "127.0.0.1".into(),
"-dir".into(), "/data".into(),
];
let norm = normalize_args_vec(args);
assert_eq!(norm, vec![
"bin", "--port", "8080", "--ip.bind", "127.0.0.1", "--dir", "/data",
]);
}
#[test]
fn test_normalize_args_double_dash_unchanged() {
let args = vec![
"bin".into(),
"--port".into(), "8080".into(),
"--master".into(), "localhost:9333".into(),
];
let norm = normalize_args_vec(args);
assert_eq!(norm, vec![
"bin", "--port", "8080", "--master", "localhost:9333",
]);
}
#[test]
fn test_normalize_args_single_char_flags_unchanged() {
let args = vec!["bin".into(), "-h".into(), "-V".into()];
let norm = normalize_args_vec(args);
assert_eq!(norm, vec!["bin", "-h", "-V"]);
}
#[test]
fn test_normalize_args_equals_format() {
let args = vec!["bin".into(), "-port=8080".into(), "-ip.bind=0.0.0.0".into()];
let norm = normalize_args_vec(args);
assert_eq!(norm, vec!["bin", "--port=8080", "--ip.bind=0.0.0.0"]);
}
#[test]
fn test_normalize_args_stop_at_double_dash() {
let args = vec!["bin".into(), "-port".into(), "8080".into(), "--".into(), "-notaflag".into()];
let norm = normalize_args_vec(args);
assert_eq!(norm, vec!["bin", "--port", "8080", "--", "-notaflag"]);
}
#[test]
fn test_parse_security_config_access_ui() {
let tmp = tempfile::NamedTempFile::new().unwrap();

28
test/volume_server/framework/cluster_rust.go

@ -185,24 +185,24 @@ func (rc *RustCluster) startRustVolume(dataDir string) error {
}
args := []string{
"--port", strconv.Itoa(rc.volumePort),
"--port.grpc", strconv.Itoa(rc.volumeGrpcPort),
"--port.public", strconv.Itoa(rc.volumePubPort),
"--ip", "127.0.0.1",
"--ip.bind", "127.0.0.1",
"--dir", dataDir,
"--max", "16",
"--master", "127.0.0.1:" + strconv.Itoa(rc.masterPort),
"--securityFile", filepath.Join(rc.configDir, "security.toml"),
"--concurrentUploadLimitMB", strconv.Itoa(rc.profile.ConcurrentUploadLimitMB),
"--concurrentDownloadLimitMB", strconv.Itoa(rc.profile.ConcurrentDownloadLimitMB),
"--preStopSeconds", "0",
"-port", strconv.Itoa(rc.volumePort),
"-port.grpc", strconv.Itoa(rc.volumeGrpcPort),
"-port.public", strconv.Itoa(rc.volumePubPort),
"-ip", "127.0.0.1",
"-ip.bind", "127.0.0.1",
"-dir", dataDir,
"-max", "16",
"-master", "127.0.0.1:" + strconv.Itoa(rc.masterPort),
"-securityFile", filepath.Join(rc.configDir, "security.toml"),
"-concurrentUploadLimitMB", strconv.Itoa(rc.profile.ConcurrentUploadLimitMB),
"-concurrentDownloadLimitMB", strconv.Itoa(rc.profile.ConcurrentDownloadLimitMB),
"-preStopSeconds", "0",
}
if rc.profile.InflightUploadTimeout > 0 {
args = append(args, "--inflightUploadDataTimeout", rc.profile.InflightUploadTimeout.String())
args = append(args, "-inflightUploadDataTimeout", rc.profile.InflightUploadTimeout.String())
}
if rc.profile.InflightDownloadTimeout > 0 {
args = append(args, "--inflightDownloadDataTimeout", rc.profile.InflightDownloadTimeout.String())
args = append(args, "-inflightDownloadDataTimeout", rc.profile.InflightDownloadTimeout.String())
}
rc.volumeCmd = exec.Command(rc.rustVolumeBinary, args...)

Loading…
Cancel
Save