mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
feat(cli): extend duration to longer units (#15040)
This PR is a proposal to improve the situation described in #14750 For some precise commands - we would like to be able to use durations bigger than hours, minutes.. This PR extends the Duration proposed by Go with : - `d` - a day or 24hours. - `y` - a year or 365 days. I also removed the default value for lifetime and instead fetch the maxLifetime value from codersdk - so by default if no value set we use the value defined in the config.
This commit is contained in:
73
cli/util.go
73
cli/util.go
@ -2,6 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -181,6 +182,78 @@ func isDigit(s string) bool {
|
||||
}) == -1
|
||||
}
|
||||
|
||||
// extendedParseDuration is a more lenient version of parseDuration that allows
|
||||
// for more flexible input formats and cumulative durations.
|
||||
// It allows for some extra units:
|
||||
// - d (days, interpreted as 24h)
|
||||
// - y (years, interpreted as 8_760h)
|
||||
//
|
||||
// FIXME: handle fractional values as discussed in https://github.com/coder/coder/pull/15040#discussion_r1799261736
|
||||
func extendedParseDuration(raw string) (time.Duration, error) {
|
||||
var d int64
|
||||
isPositive := true
|
||||
|
||||
// handle negative durations by checking for a leading '-'
|
||||
if strings.HasPrefix(raw, "-") {
|
||||
raw = raw[1:]
|
||||
isPositive = false
|
||||
}
|
||||
|
||||
if raw == "" {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", raw)
|
||||
}
|
||||
|
||||
// Regular expression to match any characters that do not match the expected duration format
|
||||
invalidCharRe := regexp.MustCompile(`[^0-9|nsuµhdym]+`)
|
||||
if invalidCharRe.MatchString(raw) {
|
||||
return 0, xerrors.Errorf("invalid duration format: %q", raw)
|
||||
}
|
||||
|
||||
// Regular expression to match numbers followed by 'd', 'y', or time units
|
||||
re := regexp.MustCompile(`(-?\d+)(ns|us|µs|ms|s|m|h|d|y)`)
|
||||
matches := re.FindAllStringSubmatch(raw, -1)
|
||||
|
||||
for _, match := range matches {
|
||||
var num int64
|
||||
num, err := strconv.ParseInt(match[1], 10, 0)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", match[1])
|
||||
}
|
||||
|
||||
switch match[2] {
|
||||
case "d":
|
||||
// we want to check if d + num * int64(24*time.Hour) would overflow
|
||||
if d > (1<<63-1)-num*int64(24*time.Hour) {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", raw)
|
||||
}
|
||||
d += num * int64(24*time.Hour)
|
||||
case "y":
|
||||
// we want to check if d + num * int64(8760*time.Hour) would overflow
|
||||
if d > (1<<63-1)-num*int64(8760*time.Hour) {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", raw)
|
||||
}
|
||||
d += num * int64(8760*time.Hour)
|
||||
case "h", "m", "s", "ns", "us", "µs", "ms":
|
||||
partDuration, err := time.ParseDuration(match[0])
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", match[0])
|
||||
}
|
||||
if d > (1<<63-1)-int64(partDuration) {
|
||||
return 0, xerrors.Errorf("invalid duration: %q", raw)
|
||||
}
|
||||
d += int64(partDuration)
|
||||
default:
|
||||
return 0, xerrors.Errorf("invalid duration unit: %q", match[2])
|
||||
}
|
||||
}
|
||||
|
||||
if !isPositive {
|
||||
return -time.Duration(d), nil
|
||||
}
|
||||
|
||||
return time.Duration(d), nil
|
||||
}
|
||||
|
||||
// parseTime attempts to parse a time (no date) from the given string using a number of layouts.
|
||||
func parseTime(s string) (time.Time, error) {
|
||||
// Try a number of possible layouts.
|
||||
|
Reference in New Issue
Block a user