feat(git): ignore repo based on exclude_folders

This commit is contained in:
Jan De Dobbeleer 2021-10-20 17:01:19 +02:00 committed by Jan De Dobbeleer
parent 37659aab70
commit cdc2998ed8
7 changed files with 130 additions and 74 deletions

View file

@ -72,11 +72,10 @@ func (b *Block) setStringValues() {
wg := sync.WaitGroup{}
wg.Add(len(b.Segments))
defer wg.Wait()
cwd := b.env.getcwd()
for _, segment := range b.Segments {
go func(s *Segment) {
defer wg.Done()
s.setStringValue(b.env, cwd)
s.setStringValue(b.env)
}(segment)
}
}
@ -184,7 +183,7 @@ func (b *Block) debug() (int, []*SegmentTiming) {
largestSegmentNameLength := 0
for _, segment := range b.Segments {
err := segment.mapSegmentWithWriter(b.env)
if err != nil || !segment.shouldIncludeFolder(b.env.getcwd()) {
if err != nil || !segment.shouldIncludeFolder() {
continue
}
var segmentTiming SegmentTiming

View file

@ -1,7 +1,9 @@
package main
import (
"fmt"
"regexp"
"strings"
"sync"
)
@ -77,3 +79,25 @@ func matchString(pattern, text string) bool {
re := getCompiledRegex(pattern)
return re.MatchString(text)
}
func dirMatchesOneOf(env environmentInfo, dir string, regexes []string) bool {
normalizedCwd := strings.ReplaceAll(dir, "\\", "/")
normalizedHomeDir := strings.ReplaceAll(env.homeDir(), "\\", "/")
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = normalizedHomeDir + normalizedElement[1:]
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
goos := env.getRuntimeGOOS()
if goos == windowsPlatform || goos == darwinPlatform {
pattern = "(?i)" + pattern
}
matched := matchString(pattern, normalizedCwd)
if matched {
return true
}
}
return false
}

40
src/regex_test.go Normal file
View file

@ -0,0 +1,40 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDirMatchesOneOf(t *testing.T) {
cases := []struct {
GOOS string
HomeDir string
Dir string
Pattern string
Expected bool
}{
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill", Pattern: "/home/bill", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/Foo", Expected: false},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "~", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true},
}
for _, tc := range cases {
env := new(MockedEnvironment)
env.On("getRuntimeGOOS", nil).Return(tc.GOOS)
env.On("homeDir", nil).Return(tc.HomeDir)
got := dirMatchesOneOf(env, tc.Dir, []string{tc.Pattern})
assert.Equal(t, tc.Expected, got)
}
}

View file

@ -3,7 +3,6 @@ package main
import (
"errors"
"fmt"
"strings"
"time"
)
@ -146,13 +145,13 @@ func (segment *Segment) getValue(property Property, defaultValue string) string
return defaultValue
}
func (segment *Segment) shouldIncludeFolder(cwd string) bool {
cwdIncluded := segment.cwdIncluded(cwd)
cwdExcluded := segment.cwdExcluded(cwd)
func (segment *Segment) shouldIncludeFolder() bool {
cwdIncluded := segment.cwdIncluded()
cwdExcluded := segment.cwdExcluded()
return (cwdIncluded && !cwdExcluded)
}
func (segment *Segment) cwdIncluded(cwd string) bool {
func (segment *Segment) cwdIncluded() bool {
value, ok := segment.Properties[IncludeFolders]
if !ok {
// IncludeFolders isn't specified, everything is included
@ -166,38 +165,16 @@ func (segment *Segment) cwdIncluded(cwd string) bool {
return true
}
return segment.cwdMatchesOneOf(cwd, list)
return dirMatchesOneOf(segment.env, segment.env.getcwd(), list)
}
func (segment *Segment) cwdExcluded(cwd string) bool {
func (segment *Segment) cwdExcluded() bool {
value, ok := segment.Properties[ExcludeFolders]
if !ok {
value = segment.Properties[IgnoreFolders]
}
list := parseStringArray(value)
return segment.cwdMatchesOneOf(cwd, list)
}
func (segment *Segment) cwdMatchesOneOf(cwd string, regexes []string) bool {
normalizedCwd := strings.ReplaceAll(cwd, "\\", "/")
normalizedHomeDir := strings.ReplaceAll(segment.env.homeDir(), "\\", "/")
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = normalizedHomeDir + normalizedElement[1:]
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
goos := segment.env.getRuntimeGOOS()
if goos == windowsPlatform || goos == darwinPlatform {
pattern = "(?i)" + pattern
}
matched := matchString(pattern, normalizedCwd)
if matched {
return true
}
}
return false
return dirMatchesOneOf(segment.env, segment.env.getcwd(), list)
}
func (segment *Segment) getColor(templates []string, defaultColor string) string {
@ -297,7 +274,7 @@ func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
return errors.New("unable to map writer")
}
func (segment *Segment) setStringValue(env environmentInfo, cwd string) {
func (segment *Segment) setStringValue(env environmentInfo) {
defer func() {
err := recover()
if err == nil {
@ -310,7 +287,7 @@ func (segment *Segment) setStringValue(env environmentInfo, cwd string) {
segment.active = true
}()
err := segment.mapSegmentWithWriter(env)
if err != nil || !segment.shouldIncludeFolder(cwd) {
if err != nil || !segment.shouldIncludeFolder() {
return
}
if segment.enabled() {

View file

@ -135,6 +135,10 @@ func (g *git) enabled() bool {
if err != nil {
return false
}
if g.shouldIgnoreRootRepository(gitdir.parentFolder) {
return false
}
g.repo = &gitRepo{}
if gitdir.isDir {
g.repo.gitWorkingFolder = gitdir.path
@ -159,6 +163,18 @@ func (g *git) enabled() bool {
return false
}
func (g *git) shouldIgnoreRootRepository(rootDir string) bool {
if g.props == nil || g.props.values == nil {
return false
}
value, ok := g.props.values[ExcludeFolders]
if !ok {
return false
}
excludedFolders := parseStringArray(value)
return dirMatchesOneOf(g.env, rootDir, excludedFolders)
}
func (g *git) string() string {
statusColorsEnabled := g.props.getBool(StatusColorsEnabled, false)
displayStatus := g.props.getBool(DisplayStatus, false)

View file

@ -925,3 +925,36 @@ func TestTruncateBranch(t *testing.T) {
assert.Equal(t, tc.Expected, g.truncateBranch(tc.Branch), tc.Case)
}
}
func TestShouldIgnoreRootRepository(t *testing.T) {
cases := []struct {
Case string
Dir string
Expected bool
}{
{Case: "inside excluded", Dir: "/home/bill/repo"},
{Case: "oustide excluded", Dir: "/home/melinda"},
{Case: "excluded exact match", Dir: "/home/gates", Expected: true},
{Case: "excluded inside match", Dir: "/home/gates/bill", Expected: true},
}
for _, tc := range cases {
props := map[Property]interface{}{
ExcludeFolders: []string{
"/home/bill",
"/home/gates.*",
},
}
env := new(MockedEnvironment)
env.On("homeDir", nil).Return("/home/bill")
env.On("getRuntimeGOOS", nil).Return(windowsPlatform)
git := &git{
props: &properties{
values: props,
},
env: env,
}
got := git.shouldIgnoreRootRepository(tc.Dir)
assert.Equal(t, tc.Expected, got, tc.Case)
}
}

View file

@ -84,6 +84,7 @@ func TestShouldIncludeFolder(t *testing.T) {
env := new(MockedEnvironment)
env.On("getRuntimeGOOS", nil).Return(linuxPlatform)
env.On("homeDir", nil).Return("")
env.On("getcwd", nil).Return(cwd)
segment := &Segment{
Properties: map[Property]interface{}{
IncludeFolders: tc.IncludeFolders,
@ -91,7 +92,7 @@ func TestShouldIncludeFolder(t *testing.T) {
},
env: env,
}
got := segment.shouldIncludeFolder(cwd)
got := segment.shouldIncludeFolder()
assert.Equal(t, tc.Expected, got, tc.Case)
}
}
@ -100,6 +101,7 @@ func TestShouldIncludeFolderRegexInverted(t *testing.T) {
env := new(MockedEnvironment)
env.On("getRuntimeGOOS", nil).Return(linuxPlatform)
env.On("homeDir", nil).Return("")
env.On("getcwd", nil).Return(cwd)
segment := &Segment{
Properties: map[Property]interface{}{
ExcludeFolders: []string{"(?!Projects[\\/]).*"},
@ -113,13 +115,14 @@ func TestShouldIncludeFolderRegexInverted(t *testing.T) {
assert.Equal(t, "regexp: Compile(`^(?!Projects[\\/]).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`", err)
}
}()
segment.shouldIncludeFolder(cwd)
segment.shouldIncludeFolder()
}
func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) {
env := new(MockedEnvironment)
env.On("getRuntimeGOOS", nil).Return(linuxPlatform)
env.On("homeDir", nil).Return("")
env.On("getcwd", nil).Return(cwd)
segment := &Segment{
Properties: map[Property]interface{}{
ExcludeFolders: []string{"(?!Projects/).*"},
@ -133,7 +136,7 @@ func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) {
assert.Equal(t, "regexp: Compile(`^(?!Projects/).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`", err)
}
}()
segment.shouldIncludeFolder(cwd)
segment.shouldIncludeFolder()
}
func TestGetColors(t *testing.T) {
@ -208,39 +211,3 @@ func TestGetColors(t *testing.T) {
assert.Equal(t, tc.ExpectedColor, color, tc.Case)
}
}
func TestCwdMatchesOneOf(t *testing.T) {
cases := []struct {
GOOS string
HomeDir string
Cwd string
Pattern string
Expected bool
}{
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill", Pattern: "/home/bill", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/Foo", Expected: false},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "~", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true},
}
for _, tc := range cases {
env := new(MockedEnvironment)
env.On("getRuntimeGOOS", nil).Return(tc.GOOS)
env.On("homeDir", nil).Return(tc.HomeDir)
segment := &Segment{
env: env,
}
got := segment.cwdMatchesOneOf(tc.Cwd, []string{tc.Pattern})
assert.Equal(t, tc.Expected, got)
}
}