]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
enhance: Support h/m/ms suffixes for durations as well
authorJoel Rosdahl <joel@rosdahl.net>
Sun, 26 Oct 2025 20:35:19 +0000 (21:35 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 3 Nov 2025 20:03:29 +0000 (21:03 +0100)
src/ccache/core/mainoptions.cpp
src/ccache/util/string.cpp
src/ccache/util/string.hpp
unittest/test_util_string.cpp

index d00b38b8b4b939396d81287e68227f4a8251422b..95796fd025e26082422a1e7c8d41b8fa6503b545 100644 (file)
@@ -643,7 +643,9 @@ process_main_options(int argc, const char* const* argv)
     }
 
     case EVICT_OLDER_THAN: {
-      evict_max_age = util::value_or_throw<Error>(util::parse_duration(arg));
+      auto duration = util::value_or_throw<Error>(util::parse_duration(arg));
+      evict_max_age =
+        std::chrono::duration_cast<std::chrono::seconds>(duration).count();
       break;
     }
 
index e7dea93b92e5b7d778e85db19a80fddba9c9c8e2..048451aa10aeaa0996305c762a441cf958f3f17b 100644 (file)
@@ -282,29 +282,49 @@ parse_double(const std::string& value)
   }
 }
 
-tl::expected<uint64_t, std::string>
+tl::expected<std::chrono::milliseconds, std::string>
 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<int64_t, std::string>
index 5585c86c8523b2fcab0677b06b4c929946e653ee..591110486a7449fc16f76688a16573d1c7245d19 100644 (file)
@@ -131,9 +131,10 @@ tl::expected<Bytes, std::string> parse_base16(std::string_view hex_string);
 // Returns an error string if `value` cannot be parsed as a double.
 tl::expected<double, std::string> parse_double(const std::string& value);
 
-// Parse `duration`, an unsigned integer with d (days) or s (seconds) suffix,
-// into seconds.
-tl::expected<uint64_t, std::string> 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<std::chrono::milliseconds, std::string>
+parse_duration(std::string_view duration);
 
 // Parse a string into a signed integer.
 //
index 5bcf210b345a344d1df745bcb69cdb39643f567f..21940e0f94ffdedd15903e278fa086240509a452 100644 (file)
@@ -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")