feat(cli): rsync short-option clustering and inline/attached values (#285)

Implement rsync 3.4.1 client-CLI parity:
- cluster boolean shorts (-av, -aAX, -rlpt) and accept attached values
  (-B1048576, -essh, -Mfoo); add the -r, -b, -L and -B short aliases
  (-r is a faithful no-op since FastSync is always recursive)
- stop OPT_NOOP (-s/--secluded-args, -r/--recursive) from swallowing the
  next argv
- add inline --opt=value for every value-taking long option, including
  --exclude/--include/--exclude-from/--include-from/--log-file (#291)
- accept --port on the server CLI in addition to -p (#296)
- reject unknown flags naming the flag and stating it is unsupported

Unit tests cover clustering, attached/inline values, the OPT_NOOP
argument-consumption fix and rejected shorts.
This commit is contained in:
2026-09-15 21:12:53 +02:00
parent d1a567f7e3
commit 23552e823d
6 changed files with 545 additions and 103 deletions
+26
View File
@@ -234,6 +234,31 @@ static void test_server_cli_password_requires_daemon() {
server_cli_options_free(&opts);
}
/* --port is the rsync-style alias for -p, in both the separate and =value
* spellings; an invalid value is still validated. */
static void test_server_cli_port_alias() {
const char* a1[] = {"fastsync-server", "--port", "9000"};
ServerCliOptions opts;
EXPECT_EQ_INT(parse_ok(a1, 3, &opts), 0);
EXPECT_EQ_INT(opts.port, 9000);
EXPECT_TRUE(opts.port_set);
server_cli_options_free(&opts);
const char* a2[] = {"fastsync-server", "--port=9001"};
ServerCliOptions opts2;
EXPECT_EQ_INT(parse_ok(a2, 2, &opts2), 0);
EXPECT_EQ_INT(opts2.port, 9001);
EXPECT_TRUE(opts2.port_set);
server_cli_options_free(&opts2);
char err[128];
ServerCliOptions opts3;
const char* a3[] = {"fastsync-server", "--port", "notaport"};
EXPECT_EQ_INT(server_cli_parse(3, (char**)a3, &opts3, err, sizeof(err)), -1);
EXPECT_TRUE(strstr(err, "invalid port") != NULL);
server_cli_options_free(&opts3);
}
static void test_server_cli_help() {
char err[256];
const char* a1[] = {"s", "--help"};
@@ -254,5 +279,6 @@ void test_server_cli() {
test_server_cli_password_requires_daemon();
test_server_cli_no_super();
test_server_cli_allow_super();
test_server_cli_port_alias();
test_server_cli_help();
}