Dan Anglin
0ad02e0af4
This commit adds a new parser for the internal time duration flag value (TimeDurationValue). Previously this used the parser from the time package from the standard library but this was limited to parsing units of time up to hours. The new parser allows users to specify duration in days, hours, minutes, seconds and a combination of the above. It is quite flexible in the way users format their string input. Additonal changes: - Added unit tests for the command-line parsing of the TimeDurationValue type. - Updated the unit tests for the BoolPtrValue type. - Updated documentation. PR: #55
79 lines
2 KiB
Go
79 lines
2 KiB
Go
package flag
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const timeDurationRegexPattern string = `[0-9]{1,4}\s+(days?|hours?|minutes?|seconds?)`
|
|
|
|
type TimeDurationValue struct {
|
|
Duration time.Duration
|
|
}
|
|
|
|
func NewTimeDurationValue() TimeDurationValue {
|
|
return TimeDurationValue{
|
|
Duration: time.Duration(0),
|
|
}
|
|
}
|
|
|
|
func (v TimeDurationValue) String() string {
|
|
return v.Duration.String()
|
|
}
|
|
|
|
func (v *TimeDurationValue) Set(value string) error {
|
|
pattern := regexp.MustCompile(timeDurationRegexPattern)
|
|
matches := pattern.FindAllString(value, -1)
|
|
|
|
days, hours, minutes, seconds := 0, 0, 0, 0
|
|
|
|
var err error
|
|
|
|
for ind := range len(matches) {
|
|
switch {
|
|
case strings.Contains(matches[ind], "day"):
|
|
days, err = parseInt(matches[ind])
|
|
if err != nil {
|
|
return fmt.Errorf("unable to parse the number of days from %s: %w", matches[ind], err)
|
|
}
|
|
case strings.Contains(matches[ind], "hour"):
|
|
hours, err = parseInt(matches[ind])
|
|
if err != nil {
|
|
return fmt.Errorf("unable to parse the number of hours from %s: %w", matches[ind], err)
|
|
}
|
|
case strings.Contains(matches[ind], "minute"):
|
|
minutes, err = parseInt(matches[ind])
|
|
if err != nil {
|
|
return fmt.Errorf("unable to parse the number of minutes from %s: %w", matches[ind], err)
|
|
}
|
|
case strings.Contains(matches[ind], "second"):
|
|
seconds, err = parseInt(matches[ind])
|
|
if err != nil {
|
|
return fmt.Errorf("unable to parse the number of seconds from %s: %w", matches[ind], err)
|
|
}
|
|
}
|
|
}
|
|
|
|
durationValue := (days * 86400) + (hours * 3600) + (minutes * 60) + seconds
|
|
|
|
v.Duration = time.Duration(durationValue) * time.Second
|
|
|
|
return nil
|
|
}
|
|
|
|
func parseInt(text string) (int, error) {
|
|
split := strings.SplitN(text, " ", 2)
|
|
if len(split) != 2 {
|
|
return 0, fmt.Errorf("unexpected number of split for %s: want 2, got %d", text, len(split))
|
|
}
|
|
|
|
output, err := strconv.Atoi(split[0])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("unable to convert %s to an integer: %w", text, err)
|
|
}
|
|
|
|
return output, nil
|
|
}
|