diff --git a/RSYNC_COMPAT.md b/RSYNC_COMPAT.md index 92fa333..a3d6f36 100644 --- a/RSYNC_COMPAT.md +++ b/RSYNC_COMPAT.md @@ -23,7 +23,7 @@ This document maps rsync's full feature set to FastSync's current implementation | `-q`, `--quiet` | Suppress non-error messages | ❌ Not Implemented | Removed because it had no effect | | `--help` | Show help | ✅ Implemented | Prints usage and exits; `-h` is not accepted | | `-V`, `--version` | Print version | ✅ Implemented | | -| `--info=FLAGS` | Fine-grained info verbosity | ✅ Implemented | Supports `copy`, `misc`, `skip`, `stats`, and `none`; unsupported names are rejected | +| `--info=FLAGS` | Fine-grained info verbosity | ✅ Implemented | Supports `copy`, `misc`, `skip`, `stats`, and `none`; explicit flags override `--verbose`, and `none` suppresses info output; unsupported names are rejected | | `--debug=FLAGS` | Fine-grained debug verbosity | ❌ Not Implemented | Removed because it had no effect | | `--stderr=MODE` | Change stderr output mode | ❌ Not Implemented | | | `--no-motd` | Suppress daemon MOTD | ❌ Not Implemented | | diff --git a/src/client/usage.c b/src/client/usage.c index 581f414..95f444e 100644 --- a/src/client/usage.c +++ b/src/client/usage.c @@ -38,6 +38,7 @@ void print_usage(void) { printf(" -f Enable sendfile (TCP only, not with -c or -s)\n"); printf(" -v, --verbose Enable debug logging\n"); printf(" --info=FLAGS Fine-grained info: copy,misc,skip,stats,all,none\n"); + printf(" none suppresses info even with --verbose\n"); printf(" -M, --preserve Preserve file metadata\n"); printf(" --chunk-size Chunk size in bytes (default: %d)\n", DEFAULT_CHUNK_SIZE); printf(" --source-dir Source directory\n"); diff --git a/src/shared/log.c b/src/shared/log.c index 29d2501..899894c 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -1,5 +1,6 @@ #include "log.h" #include +#include #include #include #include @@ -8,6 +9,7 @@ static const char* log_level_strings[] = {"DEBUG", "INFO", "WARN", "ERROR"}; static LogLevel current_log_level = LOG_LEVEL_WARNING; static uint32_t info_flags = 0; +static bool info_flags_explicit = false; static FILE* log_fp = NULL; void set_log_level(LogLevel level) { @@ -16,6 +18,7 @@ void set_log_level(LogLevel level) { void set_log_info_flags(uint32_t flags) { info_flags = flags; + info_flags_explicit = true; } uint32_t get_log_info_flags(void) { @@ -63,7 +66,8 @@ void log_message(LogLevel log_level, const char* format, ...) { } void log_info_message(LogInfoFlag flag, const char* format, ...) { - if ((info_flags & flag) == 0 && current_log_level > LOG_LEVEL_DEBUG) + if ((info_flags_explicit && (info_flags & flag) == 0) || + (!info_flags_explicit && current_log_level > LOG_LEVEL_DEBUG)) return; time_t now = time(NULL); diff --git a/tests/integration/test_features.py b/tests/integration/test_features.py index f0836cb..1e0eeab 100644 --- a/tests/integration/test_features.py +++ b/tests/integration/test_features.py @@ -295,6 +295,19 @@ class TestInfo: assert result.returncode != 0 assert "unsupported --info flag" in result.stderr + @pytest.mark.parametrize("flags", [ + ["--info=none", "--verbose"], + ["--verbose", "--info=none"], + ]) + def test_info_none_suppresses_verbose_info(self, shared_server, flags): + clean_dir(DEST_DIR) + result, _ = run_client(SOURCE_DIR, DEST_DIR, flags=flags, port=shared_server.port) + assert result.returncode == 0, f"Info sync failed: {(result.stderr or result.stdout)[:200]}" + output = result.stdout + result.stderr + assert "[INFO]" not in output + assert "Transferring" not in output + assert "Transfer summary:" not in output + class TestBandwidthLimit: def test_bwlimit_runs(self, shared_server): diff --git a/tests/test_client_cli.c b/tests/test_client_cli.c index d303f7a..bc75149 100644 --- a/tests/test_client_cli.c +++ b/tests/test_client_cli.c @@ -336,13 +336,22 @@ static void test_parse_args_info_flags() { } static void test_parse_args_info_verbose_order() { - Config* cfg = config_create(); - char* argv[] = {"fastsync", "--info=copy", "--verbose", "/src", "/dst"}; + char* argv_info_first[] = {"fastsync", "--info=none", "--verbose", "/src", "/dst"}; + char* argv_verbose_first[] = {"fastsync", "--verbose", "--info=none", "/src", "/dst"}; int positional_args[2]; int positional_count = 0; - EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), 0); - EXPECT_EQ_INT(get_log_info_flags(), LOG_INFO_COPY); + Config* cfg = config_create(); + EXPECT_EQ_INT(parse_args(cfg, 5, argv_info_first, positional_args, &positional_count), 0); + EXPECT_EQ_INT(cfg->info_level, 0); + EXPECT_EQ_INT(get_log_info_flags(), 0); + config_delete(cfg); + + cfg = config_create(); + positional_count = 0; + EXPECT_EQ_INT(parse_args(cfg, 5, argv_verbose_first, positional_args, &positional_count), 0); + EXPECT_EQ_INT(cfg->info_level, 0); + EXPECT_EQ_INT(get_log_info_flags(), 0); config_delete(cfg); }