From: Joel Rosdahl Date: Sun, 26 Oct 2025 20:35:19 +0000 (+0100) Subject: enhance: Support h/m/ms suffixes for durations as well X-Git-Tag: v4.13~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e0279c111766750fb22b01fe8b136fa003fd0ea;p=thirdparty%2Fccache.git enhance: Support h/m/ms suffixes for durations as well --- diff --git a/src/ccache/core/mainoptions.cpp b/src/ccache/core/mainoptions.cpp index d00b38b8..95796fd0 100644 --- a/src/ccache/core/mainoptions.cpp +++ b/src/ccache/core/mainoptions.cpp @@ -643,7 +643,9 @@ process_main_options(int argc, const char* const* argv) } case EVICT_OLDER_THAN: { - evict_max_age = util::value_or_throw(util::parse_duration(arg)); + auto duration = util::value_or_throw(util::parse_duration(arg)); + evict_max_age = + std::chrono::duration_cast(duration).count(); break; } diff --git a/src/ccache/util/string.cpp b/src/ccache/util/string.cpp index e7dea93b..048451aa 100644 --- a/src/ccache/util/string.cpp +++ b/src/ccache/util/string.cpp @@ -282,29 +282,49 @@ parse_double(const std::string& value) } } -tl::expected +tl::expected parse_duration(std::string_view duration) { - uint64_t factor = 0; - char last_ch = duration.empty() ? '\0' : duration[duration.length() - 1]; - - switch (last_ch) { - case 'd': - factor = 24 * 60 * 60; - break; - case 's': - factor = 1; - break; - default: - return tl::unexpected(FMT( - "invalid suffix (supported: d (day) and s (second)): \"{}\"", duration)); - } - - auto value = parse_unsigned(duration.substr(0, duration.length() - 1)); - if (!value) { - return value; - } - return factor * *value; + if (duration.empty()) { + return tl::unexpected("invalid empty duration: \"\""); + } + + uint64_t factor_ms = 0; + size_t suffix_len = 1; + char last_ch = duration.back(); + + // Check for two-character suffix "ms" + if (duration.length() >= 2 && last_ch == 's' + && duration[duration.length() - 2] == 'm') { + factor_ms = 1; + suffix_len = 2; + } else { + // Single-character suffixes + switch (last_ch) { + case 's': + factor_ms = 1000; + break; + case 'm': + factor_ms = 60 * 1000; + break; + case 'h': + factor_ms = 60 * 60 * 1000; + break; + case 'd': + factor_ms = 24 * 60 * 60 * 1000; + break; + default: + return tl::unexpected( + FMT("invalid suffix (supported: ms (millisecond), s (second), m " + "(minute), h (hour), d (day)): \"{}\"", + duration)); + } + } + + TRY_ASSIGN( + auto value, + parse_unsigned(duration.substr(0, duration.length() - suffix_len))); + return std::chrono::milliseconds(factor_ms * value); } tl::expected diff --git a/src/ccache/util/string.hpp b/src/ccache/util/string.hpp index 5585c86c..59111048 100644 --- a/src/ccache/util/string.hpp +++ b/src/ccache/util/string.hpp @@ -131,9 +131,10 @@ tl::expected parse_base16(std::string_view hex_string); // Returns an error string if `value` cannot be parsed as a double. tl::expected parse_double(const std::string& value); -// Parse `duration`, an unsigned integer with d (days) or s (seconds) suffix, -// into seconds. -tl::expected parse_duration(std::string_view duration); +// Parse `duration`, an unsigned integer with ms (milliseconds), s (seconds), m +// (minutes), h (hours), or d (days) suffix, into milliseconds. +tl::expected +parse_duration(std::string_view duration); // Parse a string into a signed integer. // diff --git a/unittest/test_util_string.cpp b/unittest/test_util_string.cpp index 5bcf210b..21940e0f 100644 --- a/unittest/test_util_string.cpp +++ b/unittest/test_util_string.cpp @@ -404,16 +404,33 @@ TEST_CASE("util::parse_double") TEST_CASE("util::parse_duration") { - CHECK(*util::parse_duration("0s") == 0); - CHECK(*util::parse_duration("2s") == 2); - CHECK(*util::parse_duration("1d") == 3600 * 24); - CHECK(*util::parse_duration("2d") == 2 * 3600 * 24); + CHECK(*util::parse_duration("0s") == 0ms); + CHECK(*util::parse_duration("2s") == 2000ms); + CHECK(*util::parse_duration("1ms") == 1ms); + CHECK(*util::parse_duration("500ms") == 500ms); + CHECK(*util::parse_duration("1m") == 60000ms); + CHECK(*util::parse_duration("2m") == 120000ms); + CHECK(*util::parse_duration("1h") == 3600000ms); + CHECK(*util::parse_duration("2h") == 7200000ms); + CHECK(*util::parse_duration("1d") == 86400000ms); + CHECK(*util::parse_duration("2d") == 172800000ms); + + CHECK(util::parse_duration("d").error() == "invalid unsigned integer: \"\""); + CHECK(util::parse_duration("xd").error() + == "invalid unsigned integer: \"x\""); + CHECK(util::parse_duration("-2d").error() + == "invalid unsigned integer: \"-2\""); + CHECK(util::parse_duration("-2").error() - == "invalid suffix (supported: d (day) and s (second)): \"-2\""); + == "invalid suffix (supported: ms (millisecond), s (second), m " + "(minute), h (hour), d (day)): \"-2\""); CHECK(util::parse_duration("2x").error() - == "invalid suffix (supported: d (day) and s (second)): \"2x\""); + == "invalid suffix (supported: ms (millisecond), s (second), m " + "(minute), h (hour), d (day)): \"2x\""); CHECK(util::parse_duration("2").error() - == "invalid suffix (supported: d (day) and s (second)): \"2\""); + == "invalid suffix (supported: ms (millisecond), s (second), m " + "(minute), h (hour), d (day)): \"2\""); + CHECK(util::parse_duration("").error() == "invalid empty duration: \"\""); } TEST_CASE("util::parse_signed")