Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 55b5d73

Browse files
authored
Merge pull request #695 from darkowlzz/grep-multiple-patterns-pathspec
git: Worktree.Grep() support multiple patterns and pathspecs
2 parents 5c2966c + 4ead334 commit 55b5d73

File tree

3 files changed

+124
-35
lines changed

3 files changed

+124
-35
lines changed

options.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -369,16 +369,16 @@ type CleanOptions struct {
369369

370370
// GrepOptions describes how a grep should be performed.
371371
type GrepOptions struct {
372-
// Pattern is a compiled Regexp object to be matched.
373-
Pattern *regexp.Regexp
372+
// Patterns are compiled Regexp objects to be matched.
373+
Patterns []*regexp.Regexp
374374
// InvertMatch selects non-matching lines.
375375
InvertMatch bool
376376
// CommitHash is the hash of the commit from which worktree should be derived.
377377
CommitHash plumbing.Hash
378378
// ReferenceName is the branch or tag name from which worktree should be derived.
379379
ReferenceName plumbing.ReferenceName
380-
// PathSpec is a compiled Regexp object of pathspec to use in the matching.
381-
PathSpec *regexp.Regexp
380+
// PathSpecs are compiled Regexp objects of pathspec to use in the matching.
381+
PathSpecs []*regexp.Regexp
382382
}
383383

384384
var (

worktree.go

+61-23
Original file line numberDiff line numberDiff line change
@@ -765,50 +765,88 @@ func (w *Worktree) Grep(opts *GrepOptions) ([]GrepResult, error) {
765765

766766
// findMatchInFiles takes a FileIter, worktree name and GrepOptions, and
767767
// returns a slice of GrepResult containing the result of regex pattern matching
768-
// in the file content.
768+
// in content of all the files.
769769
func findMatchInFiles(fileiter *object.FileIter, treeName string, opts *GrepOptions) ([]GrepResult, error) {
770770
var results []GrepResult
771771

772-
// Iterate through the files and look for any matches.
773772
err := fileiter.ForEach(func(file *object.File) error {
774-
// Check if the file name matches with the pathspec.
775-
if opts.PathSpec != nil && !opts.PathSpec.MatchString(file.Name) {
773+
var fileInPathSpec bool
774+
775+
// When no pathspecs are provided, search all the files.
776+
if len(opts.PathSpecs) == 0 {
777+
fileInPathSpec = true
778+
}
779+
780+
// Check if the file name matches with the pathspec. Break out of the
781+
// loop once a match is found.
782+
for _, pathSpec := range opts.PathSpecs {
783+
if pathSpec != nil && pathSpec.MatchString(file.Name) {
784+
fileInPathSpec = true
785+
break
786+
}
787+
}
788+
789+
// If the file does not match with any of the pathspec, skip it.
790+
if !fileInPathSpec {
776791
return nil
777792
}
778793

779-
content, err := file.Contents()
794+
grepResults, err := findMatchInFile(file, treeName, opts)
780795
if err != nil {
781796
return err
782797
}
798+
results = append(results, grepResults...)
799+
800+
return nil
801+
})
802+
803+
return results, err
804+
}
783805

784-
// Split the content and make parseable line-by-line.
785-
contentByLine := strings.Split(content, "\n")
786-
for lineNum, cnt := range contentByLine {
787-
addToResult := false
788-
// Match the pattern and content.
789-
if opts.Pattern != nil && opts.Pattern.MatchString(cnt) {
806+
// findMatchInFile takes a single File, worktree name and GrepOptions,
807+
// and returns a slice of GrepResult containing the result of regex pattern
808+
// matching in the given file.
809+
func findMatchInFile(file *object.File, treeName string, opts *GrepOptions) ([]GrepResult, error) {
810+
var grepResults []GrepResult
811+
812+
content, err := file.Contents()
813+
if err != nil {
814+
return grepResults, err
815+
}
816+
817+
// Split the file content and parse line-by-line.
818+
contentByLine := strings.Split(content, "\n")
819+
for lineNum, cnt := range contentByLine {
820+
addToResult := false
821+
822+
// Match the patterns and content. Break out of the loop once a
823+
// match is found.
824+
for _, pattern := range opts.Patterns {
825+
if pattern != nil && pattern.MatchString(cnt) {
790826
// Add to result only if invert match is not enabled.
791827
if !opts.InvertMatch {
792828
addToResult = true
829+
break
793830
}
794831
} else if opts.InvertMatch {
795-
// If matching fails, and invert match is enabled, add to results.
832+
// If matching fails, and invert match is enabled, add to
833+
// results.
796834
addToResult = true
835+
break
797836
}
837+
}
798838

799-
if addToResult {
800-
results = append(results, GrepResult{
801-
FileName: file.Name,
802-
LineNumber: lineNum + 1,
803-
Content: cnt,
804-
TreeName: treeName,
805-
})
806-
}
839+
if addToResult {
840+
grepResults = append(grepResults, GrepResult{
841+
FileName: file.Name,
842+
LineNumber: lineNum + 1,
843+
Content: cnt,
844+
TreeName: treeName,
845+
})
807846
}
808-
return nil
809-
})
847+
}
810848

811-
return results, err
849+
return grepResults, nil
812850
}
813851

814852
func rmFileAndDirIfEmpty(fs billy.Filesystem, name string) error {

worktree_test.go

+59-8
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,7 @@ func (s *WorktreeSuite) TestGrep(c *C) {
13301330
{
13311331
name: "basic word match",
13321332
options: GrepOptions{
1333-
Pattern: regexp.MustCompile("import"),
1333+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
13341334
},
13351335
wantResult: []GrepResult{
13361336
{
@@ -1349,7 +1349,7 @@ func (s *WorktreeSuite) TestGrep(c *C) {
13491349
}, {
13501350
name: "case insensitive match",
13511351
options: GrepOptions{
1352-
Pattern: regexp.MustCompile(`(?i)IMport`),
1352+
Patterns: []*regexp.Regexp{regexp.MustCompile(`(?i)IMport`)},
13531353
},
13541354
wantResult: []GrepResult{
13551355
{
@@ -1368,7 +1368,7 @@ func (s *WorktreeSuite) TestGrep(c *C) {
13681368
}, {
13691369
name: "invert match",
13701370
options: GrepOptions{
1371-
Pattern: regexp.MustCompile("import"),
1371+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
13721372
InvertMatch: true,
13731373
},
13741374
dontWantResult: []GrepResult{
@@ -1388,7 +1388,7 @@ func (s *WorktreeSuite) TestGrep(c *C) {
13881388
}, {
13891389
name: "match at a given commit hash",
13901390
options: GrepOptions{
1391-
Pattern: regexp.MustCompile("The MIT License"),
1391+
Patterns: []*regexp.Regexp{regexp.MustCompile("The MIT License")},
13921392
CommitHash: plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"),
13931393
},
13941394
wantResult: []GrepResult{
@@ -1410,8 +1410,8 @@ func (s *WorktreeSuite) TestGrep(c *C) {
14101410
}, {
14111411
name: "match for a given pathspec",
14121412
options: GrepOptions{
1413-
Pattern: regexp.MustCompile("import"),
1414-
PathSpec: regexp.MustCompile("go/"),
1413+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
1414+
PathSpecs: []*regexp.Regexp{regexp.MustCompile("go/")},
14151415
},
14161416
wantResult: []GrepResult{
14171417
{
@@ -1432,7 +1432,7 @@ func (s *WorktreeSuite) TestGrep(c *C) {
14321432
}, {
14331433
name: "match at a given reference name",
14341434
options: GrepOptions{
1435-
Pattern: regexp.MustCompile("import"),
1435+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
14361436
ReferenceName: "refs/heads/master",
14371437
},
14381438
wantResult: []GrepResult{
@@ -1446,11 +1446,62 @@ func (s *WorktreeSuite) TestGrep(c *C) {
14461446
}, {
14471447
name: "ambiguous options",
14481448
options: GrepOptions{
1449-
Pattern: regexp.MustCompile("import"),
1449+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
14501450
CommitHash: plumbing.NewHash("2d55a722f3c3ecc36da919dfd8b6de38352f3507"),
14511451
ReferenceName: "somereferencename",
14521452
},
14531453
wantError: ErrHashOrReference,
1454+
}, {
1455+
name: "multiple patterns",
1456+
options: GrepOptions{
1457+
Patterns: []*regexp.Regexp{
1458+
regexp.MustCompile("import"),
1459+
regexp.MustCompile("License"),
1460+
},
1461+
},
1462+
wantResult: []GrepResult{
1463+
{
1464+
FileName: "go/example.go",
1465+
LineNumber: 3,
1466+
Content: "import (",
1467+
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1468+
},
1469+
{
1470+
FileName: "vendor/foo.go",
1471+
LineNumber: 3,
1472+
Content: "import \"fmt\"",
1473+
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1474+
},
1475+
{
1476+
FileName: "LICENSE",
1477+
LineNumber: 1,
1478+
Content: "The MIT License (MIT)",
1479+
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1480+
},
1481+
},
1482+
}, {
1483+
name: "multiple pathspecs",
1484+
options: GrepOptions{
1485+
Patterns: []*regexp.Regexp{regexp.MustCompile("import")},
1486+
PathSpecs: []*regexp.Regexp{
1487+
regexp.MustCompile("go/"),
1488+
regexp.MustCompile("vendor/"),
1489+
},
1490+
},
1491+
wantResult: []GrepResult{
1492+
{
1493+
FileName: "go/example.go",
1494+
LineNumber: 3,
1495+
Content: "import (",
1496+
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1497+
},
1498+
{
1499+
FileName: "vendor/foo.go",
1500+
LineNumber: 3,
1501+
Content: "import \"fmt\"",
1502+
TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1503+
},
1504+
},
14541505
},
14551506
}
14561507

0 commit comments

Comments
 (0)