Skip to content

Commit

Permalink
Refactor and fix find bugs
Browse files Browse the repository at this point in the history
- Watch now avoids an unnecessary waitgroup and simplifies overall flow.
- Watch now honors maxDepth parameter as well.
- Parsing logic is fully outside in the mainFind() function.
- Enhance and fix behavior of nameMatch to comply with unix
  find behavior.
- Enhance and fix behavior of maxdepth to comply with unix
  find behavior.

Fixes #2272
  • Loading branch information
harshavardhana committed Oct 6, 2017
1 parent 8f38471 commit 1c860b1
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 186 deletions.
99 changes: 81 additions & 18 deletions cmd/find-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package cmd

import (
"strings"
"time"

humanize "github.com/dustin/go-humanize"
"github.com/fatih/color"
"github.com/minio/cli"
"github.com/minio/mc/pkg/console"
"github.com/minio/mc/pkg/probe"
)

// find specific flags
Expand Down Expand Up @@ -67,17 +70,13 @@ var (
Name: "smaller",
Usage: "Match all objects smaller than specified size in units (see UNITS)",
},
cli.StringFlag{
cli.UintFlag{
Name: "maxdepth",
Usage: "Limit directory navigation to specified depth",
},
cli.BoolFlag{
Name: "watch",
Usage: "Monitor specified location for newly created objects",
},
cli.BoolFlag{
Name: "or",
Usage: "Changes the matching criteria from an \"and\" to an \"or\"",
Usage: "Monitor a specified path for newly created files and objects",
},
}
)
Expand Down Expand Up @@ -163,24 +162,45 @@ EXAMPLES:
// checkFindSyntax - validate the passed arguments
func checkFindSyntax(ctx *cli.Context) {
args := ctx.Args()

// help message on [mc][find]
if !args.Present() {
cli.ShowCommandHelpAndExit(ctx, "find", 1)
}

if ctx.Bool("watch") && !strings.Contains(args[0], "/") {
console.Println("Users must specify a bucket name for watch")
console.Fatalln()
if !ctx.Args().Present() {
args = []string{"./"} // No args just default to present directory.
}

// verify that there are no empty arguments
for _, arg := range args {
if strings.TrimSpace(arg) == "" {
fatalIf(errInvalidArgument().Trace(args...), "Unable to validate empty argument.")
}
}

// Extract input URLs and validate.
URLs := ctx.Args()
for _, url := range URLs {
_, _, err := url2Stat(url)
if err != nil && !isURLPrefixExists(url, false) {
// Bucket name empty is a valid error for 'find myminio' unless we are using watch, treat it as such.
if _, ok := err.ToGoError().(BucketNameEmpty); ok && !ctx.Bool("watch") {
continue
}
fatalIf(err.Trace(url), "Unable to stat `"+url+"`.")
}
}
}

// Find context is container to hold all parsed inputs.
type findContext struct {
*cli.Context
maxDepth uint
execCmd string
printFmt string
ignorePattern string
namePattern string
pathPattern string
regexPattern string
olderThan time.Time
newerThan time.Time
largerSize uint64
smallerSize uint64
watch bool
}

// mainFind - handler for mc find commands
Expand All @@ -193,11 +213,54 @@ func mainFind(ctx *cli.Context) error {
args := ctx.Args()

if !ctx.Args().Present() {
args = []string{"."}
args = []string{"./"} // Not args present default to present directory.
}

clnt, err := newClient(args[0])
fatalIf(err.Trace(args...), "Unable to initialize `"+args[0]+"`")

return doFind(args[0], clnt, ctx)
var (
olderThan time.Time
newerThan time.Time
)
if ctx.String("older") != "" {
olderThan, err = parseTime(ctx.String("older"))
fatalIf(err.Trace(ctx.String("older")), "Unable to parse input threshold value into time.Time")
}
if ctx.String("newer") != "" {
newerThan, err = parseTime(ctx.String("newer"))
fatalIf(err.Trace(ctx.String("newer")), "Unable to parse input threshold value into time.Time")
}

// Use 'e' to indicate Go error, this is a convention followed in `mc`. For probe.Error we call it
// 'err' and regular Go error is called as 'e'.
var e error
var (
largerSize uint64
smallerSize uint64
)
if ctx.String("larger") != "" {
largerSize, e = humanize.ParseBytes(ctx.String("larger"))
fatalIf(probe.NewError(e).Trace(ctx.String("larger")), "Unable to parse input threshold value into size bytes")
}

if ctx.String("smaller") != "" {
smallerSize, e = humanize.ParseBytes(ctx.String("smaller"))
fatalIf(probe.NewError(e).Trace(ctx.String("smaller")), "Unable to parse input threshold value into size bytes")
}

return doFind(&findContext{
Context: ctx,
maxDepth: ctx.Uint("maxdepth"),
execCmd: ctx.String("exec"),
printFmt: ctx.String("print"),
namePattern: ctx.String("name"),
pathPattern: ctx.String("path"),
regexPattern: ctx.String("regex"),
olderThan: olderThan,
newerThan: newerThan,
largerSize: largerSize,
smallerSize: smallerSize,
watch: ctx.Bool("watch"),
}, args[0], clnt)
}
Loading

0 comments on commit 1c860b1

Please sign in to comment.