Skip to content

Instantly share code, notes, and snippets.

@dolftax
Created February 18, 2019 15:28
Show Gist options
  • Save dolftax/c680127e314f35a902ae87d8537f8831 to your computer and use it in GitHub Desktop.
Save dolftax/c680127e314f35a902ae87d8537f8831 to your computer and use it in GitHub Desktop.
From 65aa0b180b547bce4ed771186e28be10762ad955 Mon Sep 17 00:00:00 2001
From: Ashish <[email protected]>
Date: Sat, 24 Nov 2018 12:14:52 +0530
Subject: [PATCH] OlderThan & NewerThan configured for Days, Hours and Minutes
Previously OlderThan and NewerThan was configured for day
which has been changed to Days, Hours and minutes.
---
cmd/cp-main.go | 32 ++--
cmd/mirror-main.go | 32 ++--
cmd/rm-main.go | 38 +++--
cmd/utils.go | 21 ++-
docs/minio-client-complete-guide.md | 4 +-
pkg/ioutils/format.go | 219 ++++++++++++++++++++++++++++
pkg/ioutils/ioutils_test.go | 39 +++++
7 files changed, 327 insertions(+), 58 deletions(-)
create mode 100644 pkg/ioutils/format.go
diff --git a/cmd/cp-main.go b/cmd/cp-main.go
index 92806b07..5ef6b10b 100644
--- a/cmd/cp-main.go
+++ b/cmd/cp-main.go
@@ -41,13 +41,13 @@ var (
Name: "recursive, r",
Usage: "copy recursively",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "older-than",
- Usage: "copy object(s) older than N days",
+ Usage: "copy objects older than L days, M hours and N minutes",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "newer-than",
- Usage: "copy object(s) newer than N days",
+ Usage: "copy objects newer than L days, M hours and N minutes",
},
cli.StringFlag{
Name: "storage-class, sc",
@@ -93,11 +93,11 @@ EXAMPLES:
4. Copy a bucket recursively from aliased Amazon S3 cloud storage to local filesystem on Windows.
$ {{.HelpName}} --recursive s3\documents\2014\ C:\Backups\2014
- 5. Copy files older than 7 days from Minio cloud storage to Amazon S3 cloud storage.
- $ {{.HelpName}} --older-than 7 play/mybucket/burningman2011/ s3/mybucket/
+ 5. Copy files older than 7 days and 10 hours from Minio cloud storage to Amazon S3 cloud storage.
+ $ {{.HelpName}} --older-than "7d10h" play/mybucket/burningman2011/ s3/mybucket/
- 6. Copy files newer than 7 days from Minio cloud storage to a local path.
- $ {{.HelpName}} --newer-than 7 play/mybucket/burningman2011/ ~/latest/
+ 6. Copy files newer than 7 days and 10 hours from Minio cloud storage to a local path.
+ $ {{.HelpName}} --newer-than "7d10h" play/mybucket/burningman2011/ ~/latest/
7. Copy an object with name containing unicode characters to Amazon S3 cloud storage.
$ {{.HelpName}} 本語 s3/andoria/
@@ -217,8 +217,8 @@ func doPrepareCopyURLs(session *sessionV8, trapCh <-chan bool, cancelCopy contex
// Access recursive flag inside the session header.
isRecursive := session.Header.CommandBoolFlags["recursive"]
- olderThan := session.Header.CommandIntFlags["older-than"]
- newerThan := session.Header.CommandIntFlags["newer-than"]
+ olderThan := session.Header.CommandStringFlags["older-than"]
+ newerThan := session.Header.CommandStringFlags["newer-than"]
encryptKeys := session.Header.CommandStringFlags["encrypt-key"]
encrypt := session.Header.CommandStringFlags["encrypt"]
encKeyDB, err := parseAndValidateEncryptionKeys(encryptKeys, encrypt)
@@ -260,12 +260,12 @@ func doPrepareCopyURLs(session *sessionV8, trapCh <-chan bool, cancelCopy contex
}
// Skip objects older than --older-than parameter if specified
- if olderThan > 0 && isOlder(cpURLs.SourceContent, olderThan) {
+ if olderThan != "" && isOlder(cpURLs.SourceContent, olderThan) {
continue
}
// Skip objects newer than --newer-than parameter if specified
- if newerThan > 0 && isNewer(cpURLs.SourceContent, newerThan) {
+ if newerThan != "" && isNewer(cpURLs.SourceContent, newerThan) {
continue
}
@@ -451,8 +451,8 @@ func mainCopy(ctx *cli.Context) error {
console.SetColor("Copy", color.New(color.FgGreen, color.Bold))
recursive := ctx.Bool("recursive")
- olderThan := ctx.Int("older-than")
- newerThan := ctx.Int("newer-than")
+ olderThan := ctx.String("older-than")
+ newerThan := ctx.String("newer-than")
storageClass := ctx.String("storage-class")
sseKeys := os.Getenv("MC_ENCRYPT_KEY")
if key := ctx.String("encrypt-key"); key != "" {
@@ -463,8 +463,8 @@ func mainCopy(ctx *cli.Context) error {
session := newSessionV8()
session.Header.CommandType = "cp"
session.Header.CommandBoolFlags["recursive"] = recursive
- session.Header.CommandIntFlags["older-than"] = olderThan
- session.Header.CommandIntFlags["newer-than"] = newerThan
+ session.Header.CommandStringFlags["older-than"] = olderThan
+ session.Header.CommandStringFlags["newer-than"] = newerThan
session.Header.CommandStringFlags["storage-class"] = storageClass
session.Header.CommandStringFlags["encrypt-key"] = sseKeys
session.Header.CommandStringFlags["encrypt"] = sse
diff --git a/cmd/mirror-main.go b/cmd/mirror-main.go
index a9ed3a3a..a680609c 100644
--- a/cmd/mirror-main.go
+++ b/cmd/mirror-main.go
@@ -71,13 +71,13 @@ var (
Name: "exclude",
Usage: "exclude object(s) that match specified object name pattern",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "older-than",
- Usage: "filter object(s) older than N days",
+ Usage: "filter object(s) older than L days, M hours and N minutes",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "newer-than",
- Usage: "filter object(s) newer than N days",
+ Usage: "filter object(s) newer than L days, M hours and N minutes",
},
cli.StringFlag{
Name: "storage-class, sc",
@@ -117,8 +117,8 @@ EXAMPLES:
2. Mirror a local folder recursively to Amazon S3 cloud storage.
$ {{.HelpName}} backup/ s3/archive
- 3. Only mirror files that are newer than 7 days to Amazon S3 cloud storage.
- $ {{.HelpName}} --newer-than 7 backup/ s3/archive
+ 3. Only mirror files that are newer than 7 days, 10 hours and 30 minutes to Amazon S3 cloud storage.
+ $ {{.HelpName}} --newer-than "7d10h30m" backup/ s3/archive
4. Mirror a bucket from aliased Amazon S3 cloud storage to a folder on Windows.
$ {{.HelpName}} s3\documents\2014\ C:\backup\2014
@@ -139,10 +139,10 @@ EXAMPLES:
$ {{.HelpName}} --exclude ".*" --exclude "*.temp" s3/test ~/test
9. Mirror objects newer than 10 days from bucket test to a local folder.
- $ {{.HelpName}} --newer-than=10 s3/test ~/localfolder
+ $ {{.HelpName}} --newer-than=10d s3/test ~/localfolder
10. Mirror objects older than 30 days from Amazon S3 bucket test to a local folder.
- $ {{.HelpName}} --older-than=30 s3/test ~/test
+ $ {{.HelpName}} --older-than=30d s3/test ~/test
11. Mirror server encrypted objects from Minio cloud storage to a bucket on Amazon S3 cloud storage
$ {{.HelpName}} --encrypt-key "minio/photos=32byteslongsecretkeymustbegiven1,s3/archive=32byteslongsecretkeymustbegiven2" minio/photos/ s3/archive/
@@ -185,7 +185,7 @@ type mirrorJob struct {
targetURL string
isFake, isRemove, isOverwrite, isWatch bool
- olderThan, newerThan int
+ olderThan, newerThan string
storageClass string
excludeOptions []string
@@ -245,7 +245,9 @@ func (mj *mirrorJob) doRemove(sURLs URLs) URLs {
}
}
- return sURLs.WithError(nil)
+ // Remove extraneous file/bucket on target.
+ err := probe.NewError(removeSingle(targetWithAlias, isIncomplete, mj.isFake, "", "", sURLs.encKeyDB))
+ return sURLs.WithError(err)
}
// doMirror - Mirror an object to multiple destination. URLs status contains a copy of sURLs and error if any.
@@ -523,12 +525,12 @@ func (mj *mirrorJob) startMirror(ctx context.Context, cancelMirror context.Cance
if sURLs.SourceContent != nil {
// Skip objects older than --older-than parameter if specified
- if mj.olderThan > 0 && isOlder(sURLs.SourceContent, mj.olderThan) {
+ if mj.olderThan != "" && isOlder(sURLs.SourceContent, mj.olderThan) {
continue
}
// Skip objects newer than --newer-than parameter if specified
- if mj.newerThan > 0 && isNewer(sURLs.SourceContent, mj.newerThan) {
+ if mj.newerThan != "" && isNewer(sURLs.SourceContent, mj.newerThan) {
continue
}
@@ -614,7 +616,7 @@ func (mj *mirrorJob) mirror(ctx context.Context, cancelMirror context.CancelFunc
}
}
-func newMirrorJob(srcURL, dstURL string, isFake, isRemove, isOverwrite, isWatch bool, excludeOptions []string, olderThan, newerThan int, storageClass string, encKeyDB map[string][]prefixSSEPair) *mirrorJob {
+func newMirrorJob(srcURL, dstURL string, isFake, isRemove, isOverwrite, isWatch bool, excludeOptions []string, olderThan, newerThan string, storageClass string, encKeyDB map[string][]prefixSSEPair) *mirrorJob {
mj := mirrorJob{
trapCh: signalTrap(os.Interrupt, syscall.SIGTERM, syscall.SIGKILL),
m: new(sync.Mutex),
@@ -691,8 +693,8 @@ func runMirror(srcURL, dstURL string, ctx *cli.Context, encKeyDB map[string][]pr
isOverwrite,
ctx.Bool("watch"),
ctx.StringSlice("exclude"),
- ctx.Int("older-than"),
- ctx.Int("newer-than"),
+ ctx.String("older-than"),
+ ctx.String("newer-than"),
ctx.String("storage-class"),
encKeyDB)
diff --git a/cmd/rm-main.go b/cmd/rm-main.go
index 274c9696..8e0a7f28 100644
--- a/cmd/rm-main.go
+++ b/cmd/rm-main.go
@@ -23,7 +23,6 @@ import (
"os"
"path/filepath"
"strings"
- "time"
"github.com/fatih/color"
"github.com/minio/cli"
@@ -31,9 +30,6 @@ import (
"github.com/minio/mc/pkg/probe"
)
-// Day time.Duration for day.
-const Day = 24 * time.Hour
-
// rm specific flags.
var (
rmFlags = []cli.Flag{
@@ -61,13 +57,13 @@ var (
Name: "stdin",
Usage: "read object names from STDIN",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "older-than",
- Usage: "remove objects older than N days",
+ Usage: "remove objects older than L days, M hours and N minutes",
},
- cli.IntFlag{
+ cli.StringFlag{
Name: "newer-than",
- Usage: "remove objects newer than N days",
+ Usage: "remove objects newer than L days, M hours and N minutes",
},
}
)
@@ -99,10 +95,10 @@ EXAMPLES:
$ {{.HelpName}} --recursive s3/jazz-songs/louis/
3. Remove all objects older than '90' days recursively from bucket 'jazz-songs' that match 'louis' prefix.
- $ {{.HelpName}} --recursive --older-than=90 s3/jazz-songs/louis/
+ $ {{.HelpName}} --recursive --older-than="90d" s3/jazz-songs/louis/
- 4. Remove all objects newer than 7 days recursively from bucket 'pop-songs'
- $ {{.HelpName}} --recursive --newer-than=7 s3/pop-songs/
+ 4. Remove all objects newer than 7 days and 10 hours recursively from bucket 'pop-songs'
+ $ {{.HelpName}} --recursive --newer-than="7d10h" s3/pop-songs/
5. Remove all objects read from STDIN.
$ {{.HelpName}} --force --stdin
@@ -110,8 +106,8 @@ EXAMPLES:
6. Remove all objects recursively from S3 host
$ {{.HelpName}} --recursive --dangerous s3
- 7. Remove all objects older than '90' days recursively from host
- $ {{.HelpName}} --recursive --dangerous --older-than=90 s3
+ 7. Remove all buckets and objects older than '90' days recursively from host
+ $ {{.HelpName}} --recursive --dangerous --older-than="90d" s3
8. Drop all incomplete uploads on 'jazz-songs' bucket.
$ {{.HelpName}} --incomplete --recursive s3/jazz-songs/
@@ -179,7 +175,7 @@ func checkRmSyntax(ctx *cli.Context, encKeyDB map[string][]prefixSSEPair) {
}
}
-func removeSingle(url string, isIncomplete bool, isFake bool, olderThan int, newerThan int, encKeyDB map[string][]prefixSSEPair) error {
+func removeSingle(url string, isIncomplete bool, isFake bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
targetAlias, targetURL, _ := mustExpandAlias(url)
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
if pErr != nil {
@@ -196,12 +192,12 @@ func removeSingle(url string, isIncomplete bool, isFake bool, olderThan int, new
}
// Skip objects older than older--than parameter if specified
- if olderThan > 0 && isOlder(content, olderThan) {
+ if olderThan != "" && isOlder(content, olderThan) {
return nil
}
// Skip objects older than older--than parameter if specified
- if newerThan > 0 && isNewer(content, newerThan) {
+ if newerThan != "" && isNewer(content, newerThan) {
return nil
}
@@ -231,7 +227,7 @@ func removeSingle(url string, isIncomplete bool, isFake bool, olderThan int, new
return nil
}
-func removeRecursive(url string, isIncomplete bool, isFake bool, olderThan int, newerThan int, encKeyDB map[string][]prefixSSEPair) error {
+func removeRecursive(url string, isIncomplete bool, isFake bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
targetAlias, targetURL, _ := mustExpandAlias(url)
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
if pErr != nil {
@@ -258,12 +254,12 @@ func removeRecursive(url string, isIncomplete bool, isFake bool, olderThan int,
urlString := content.URL.Path
// Skip objects older than --older-than parameter if specified
- if olderThan > 0 && isOlder(content, olderThan) {
+ if olderThan != "" && isOlder(content, olderThan) {
continue
}
// Skip objects newer than --newer-than parameter if specified
- if newerThan > 0 && isNewer(content, newerThan) {
+ if newerThan != "" && isNewer(content, newerThan) {
continue
}
@@ -323,8 +319,8 @@ func mainRm(ctx *cli.Context) error {
isRecursive := ctx.Bool("recursive")
isFake := ctx.Bool("fake")
isStdin := ctx.Bool("stdin")
- olderThan := ctx.Int("older-than")
- newerThan := ctx.Int("newer-than")
+ olderThan := ctx.String("older-than")
+ newerThan := ctx.String("newer-than")
// Set color.
console.SetColor("Remove", color.New(color.FgGreen, color.Bold))
diff --git a/cmd/utils.go b/cmd/utils.go
index 71f3891b..9c55d43b 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -31,6 +31,7 @@ import (
"github.com/minio/minio-go/pkg/encrypt"
"github.com/minio/mc/pkg/console"
+ "github.com/minio/mc/pkg/ioutils"
"github.com/minio/mc/pkg/probe"
)
@@ -162,15 +163,27 @@ func lineTrunc(content string, maxLen int) string {
}
// isOlder returns true if the passed object is older than olderRef
-func isOlder(c *clientContent, olderRef int) bool {
+func isOlder(c *clientContent, olderRef string) bool {
objectAge := UTCNow().Sub(c.Time)
- return objectAge < (time.Duration(olderRef) * Day)
+ var e error
+ var olderThan time.Duration
+ if olderRef != "" {
+ olderThan, e = ioutils.ParseDurationTime(olderRef)
+ fatalIf(probe.NewError(e), "Unable to parse olderThan=`"+olderRef+"`.")
+ }
+ return objectAge < olderThan
}
// isNewer returns true if the passed object is newer than newerRef
-func isNewer(c *clientContent, newerRef int) bool {
+func isNewer(c *clientContent, newerRef string) bool {
objectAge := UTCNow().Sub(c.Time)
- return objectAge > (time.Duration(newerRef) * Day)
+ var e error
+ var newerThan time.Duration
+ if newerRef != "" {
+ newerThan, e = ioutils.ParseDurationTime(newerRef)
+ fatalIf(probe.NewError(e), "Unable to parse newerThan=`"+newerRef+"`.")
+ }
+ return objectAge > newerThan
}
// getLookupType returns the minio.BucketLookupType for lookup
diff --git a/docs/minio-client-complete-guide.md b/docs/minio-client-complete-guide.md
index 8ef32e29..8ae0253b 100644
--- a/docs/minio-client-complete-guide.md
+++ b/docs/minio-client-complete-guide.md
@@ -566,10 +566,10 @@ Removing `play/mybucket/otherobject.txt`.
mc rm --incomplete play/mybucket/myobject.1gig
Removing `play/mybucket/myobject.1gig`.
```
-*Example: Remove object and output a message only if the object is created older than one day. Otherwise, the command stays quiet and nothing is printed out.*
+*Example: Remove object and output a message only if the object is created older than 1 day 2hours and 30 minutes. Otherwise, the command stays quiet and nothing is printed out.*
```sh
-mc rm -r --force --older-than=1 myminio/mybucket
+mc rm -r --force --older-than="1d2h30m" myminio/mybucket
Removing `myminio/mybucket/dayOld1.txt`.
Removing `myminio/mybucket/dayOld2.txt`.
Removing `myminio/mybucket/dayOld3.txt`.
diff --git a/pkg/ioutils/format.go b/pkg/ioutils/format.go
new file mode 100644
index 00000000..7e167e6b
--- /dev/null
+++ b/pkg/ioutils/format.go
@@ -0,0 +1,219 @@
+/*
+ * Minio Cloud Storage, (C) 2018 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ioutils
+
+import (
+ "errors"
+ "time"
+)
+
+// A Duration represents the elapsed time between two instants
+// as an int64 nanosecond count. The representation limits the
+// largest representable duration to approximately 290 years.
+type Duration int64
+
+// never printed
+var errLeadingInt = errors.New("time: bad [0-9]*")
+
+// Common durations. There is no definition for units of Day or larger
+// to avoid confusion across daylight savings time zone transitions.
+//
+// To count the number of units in a Duration, divide:
+// second := time.Second
+// fmt.Print(int64(second/time.Millisecond)) // prints 1000
+//
+// To convert an integer number of units to a Duration, multiply:
+// seconds := 10
+// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
+//
+const (
+ Nanosecond Duration = 1
+ Microsecond = 1000 * Nanosecond
+ Millisecond = 1000 * Microsecond
+ Second = 1000 * Millisecond
+ Minute = 60 * Second
+ Hour = 60 * Minute
+ Day = 24 * Hour
+)
+
+var unitMap = map[string]int64{
+ "ns": int64(Nanosecond),
+ "us": int64(Microsecond),
+ "ms": int64(Millisecond),
+ "s": int64(Second),
+ "m": int64(Minute),
+ "h": int64(Hour),
+ "d": int64(Day),
+}
+
+// ParseDurationTime parses a duration string in
+// the form "10d4h3m".
+// A duration string is a possibly signed sequence of
+// decimal numbers, each with optional fraction and a unit suffix,
+// such as "300ms", "-1.5h" or "2h45m".
+// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h", "d".
+// It add the days functionality to time.ParseDuration().
+func ParseDurationTime(s string) (time.Duration, error) {
+ // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
+ orig := s
+ var d int64
+ neg := false
+
+ // Consume [-+]?
+ if s != "" {
+ c := s[0]
+ if c == '-' || c == '+' {
+ neg = c == '-'
+ s = s[1:]
+ }
+ }
+ // Special case: if all that is left is "0", this is zero.
+ if s == "0" {
+ return 0, nil
+ }
+ if s == "" {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ for s != "" {
+ var (
+ v, f int64 // integers before, after decimal point
+ scale float64 = 1 // value = v + f/scale
+ )
+
+ var err error
+
+ // The next character must be [0-9.]
+ if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ // Consume [0-9]*
+ pl := len(s)
+ v, s, err = leadingInt(s)
+ if err != nil {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ pre := pl != len(s) // whether we consumed anything before a period
+
+ // Consume (\.[0-9]*)?
+ post := false
+ if s != "" && s[0] == '.' {
+ s = s[1:]
+ pl := len(s)
+ f, scale, s = leadingFraction(s)
+ post = pl != len(s)
+ }
+ if !pre && !post {
+ // no digits (e.g. ".s" or "-.s")
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+
+ // Consume unit.
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c == '.' || '0' <= c && c <= '9' {
+ break
+ }
+ }
+ if i == 0 {
+ return 0, errors.New("time: missing unit in duration " + orig + ". Should be of days, hours and minutes format like 7d4h20m ")
+ }
+ u := s[:i]
+ s = s[i:]
+ unit, ok := unitMap[u]
+ if !ok {
+ return 0, errors.New("time: unknown unit " + u + " in duration " + orig)
+ }
+ if v > (1<<63-1)/unit {
+ // overflow
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ v *= unit
+ if f > 0 {
+ // float64 is needed to be nanosecond accurate for fractions of hours.
+ // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
+ v += int64(float64(f) * (float64(unit) / scale))
+ if v < 0 {
+ // overflow
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ }
+ d += v
+ if d < 0 {
+ // overflow
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ }
+
+ if neg {
+ d = -d
+ }
+
+ return time.Duration(d), nil
+}
+
+// leadingInt consumes the leading [0-9]* from s.
+func leadingInt(s string) (x int64, rem string, err error) {
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if x > (1<<63-1)/10 {
+ // overflow
+ return 0, "", errLeadingInt
+ }
+ x = x*10 + int64(c) - '0'
+ if x < 0 {
+ // overflow
+ return 0, "", errLeadingInt
+ }
+ }
+ return x, s[i:], nil
+}
+
+// leadingFraction consumes the leading [0-9]* from s.
+// It is used only for fractions, so does not return an error on overflow,
+// it just stops accumulating precision.
+func leadingFraction(s string) (x int64, scale float64, rem string) {
+ i := 0
+ scale = 1
+ overflow := false
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if overflow {
+ continue
+ }
+ if x > (1<<63-1)/10 {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true
+ continue
+ }
+ y := x*10 + int64(c) - '0'
+ if y < 0 {
+ overflow = true
+ continue
+ }
+ x = y
+ scale *= 10
+ }
+ return x, scale, s[i:]
+}
diff --git a/pkg/ioutils/ioutils_test.go b/pkg/ioutils/ioutils_test.go
index beefe5a0..ebe3450e 100644
--- a/pkg/ioutils/ioutils_test.go
+++ b/pkg/ioutils/ioutils_test.go
@@ -20,6 +20,7 @@ import (
"io/ioutil"
"os"
"testing"
+ "time"
"github.com/minio/mc/pkg/ioutils"
@@ -41,3 +42,41 @@ func (s *MySuite) TestIoutils(c *C) {
c.Assert(err, IsNil)
c.Assert(status, Equals, true)
}
+
+// Test for ParseDurationTime. Validates the returned value
+// for given time value in days, hours and minute format.
+func TestParseDurationTime(t *testing.T) {
+
+ testCases := []struct {
+ timeValue string
+ expected time.Duration
+ err string
+ }{
+ // Test 1: empty string as input
+ {"", 0, "time: invalid duration "},
+ // Test 2: Input string contains 4 day, 10 hour and 3 minutes
+ {"4d10h3m", 381780000000000, ""},
+ // Test 3: Input string contains 10 day and 3 hours
+ {"10d3h", 874800000000000, ""},
+ // Test 4: Input string contains minutes and days
+ {"3m7d", 604980000000000, ""},
+ // Test 5: Input string contains unknown unit
+ {"4a3d", 0, "time: unknown unit a in duration 4a3d"},
+ // Test 6: Input string contains fractional day
+ {"1.5d", 129600000000000, ""},
+ // Test 6: Input string contains fractional day and hour
+ {"2.5d1.5h", 221400000000000, ""},
+ // Test 7: Input string contains fractional day , hour and minute
+ {"2.5d1.5h3.5m", 221610000000000, ""},
+ }
+
+ for _, testCase := range testCases {
+ myVal, err := ioutils.ParseDurationTime(testCase.timeValue)
+ if err != nil && err.Error() != testCase.err {
+ t.Error()
+ }
+ if myVal != testCase.expected {
+ t.Error()
+ }
+ }
+}
--
2.20.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment