package gitignore
import (
"os"
"os/user"
"strconv"
"strings"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
. "gopkg.in/check.v1"
)
type MatcherSuite struct {
GFS billy.Filesystem // git repository root
RFS billy.Filesystem // root that contains user home
RFSR billy.Filesystem // root that contains user home, but with relative ~/.gitignore_global
RFSU billy.Filesystem // root that contains user home, but with relative ~user/.gitignore_global
MCFS billy.Filesystem // root that contains user home, but missing ~/.gitconfig
MEFS billy.Filesystem // root that contains user home, but missing excludesfile entry
MIFS billy.Filesystem // root that contains user home, but missing .gitignore
SFS billy.Filesystem // root that contains /etc/gitconfig
}
var _ = Suite(&MatcherSuite{})
func (s *MatcherSuite) SetUpTest(c *C) {
// setup generic git repository root
fs := memfs.New()
err := fs.MkdirAll(".git/info", os.ModePerm)
c.Assert(err, IsNil)
f, err := fs.Create(".git/info/exclude")
c.Assert(err, IsNil)
_, err = f.Write([]byte("exclude.crlf\r\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create(".gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("vendor/g*/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("ignore.crlf\r\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("ignore_dir\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = fs.MkdirAll("vendor", os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create("vendor/.gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("!github.com/\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = fs.MkdirAll("ignore_dir", os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create("ignore_dir/.gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("!file\n"))
c.Assert(err, IsNil)
_, err = fs.Create("ignore_dir/file")
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = fs.MkdirAll("another", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("exclude.crlf", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("ignore.crlf", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("vendor/github.com", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("vendor/gopkg.in", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("multiple/sub/ignores/first", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("multiple/sub/ignores/second", os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create("multiple/sub/ignores/first/.gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("ignore_dir\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create("multiple/sub/ignores/second/.gitignore")
c.Assert(err, IsNil)
_, err = f.Write([]byte("ignore_dir\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
err = fs.MkdirAll("multiple/sub/ignores/first/ignore_dir", os.ModePerm)
c.Assert(err, IsNil)
err = fs.MkdirAll("multiple/sub/ignores/second/ignore_dir", os.ModePerm)
c.Assert(err, IsNil)
s.GFS = fs
// setup root that contains user home
home, err := os.UserHomeDir()
c.Assert(err, IsNil)
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, gitconfigFile))
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(" excludesfile = " + strconv.Quote(fs.Join(home, ".gitignore_global")) + "\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, ".gitignore_global"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.RFS = fs
// root that contains user home, but with relative ~/.gitignore_global
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, gitconfigFile))
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(" excludesfile = ~/.gitignore_global" + "\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, ".gitignore_global"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.RFSR = fs
// root that contains user home, but with relative ~user/.gitignore_global
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, gitconfigFile))
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
currentUser, err := user.Current()
c.Assert(err, IsNil)
// remove domain for windows
username := currentUser.Username[strings.Index(currentUser.Username, "\\")+1:]
_, err = f.Write([]byte(" excludesfile = ~" + username + "/.gitignore_global" + "\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, ".gitignore_global"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.RFSU = fs
// root that contains user home, but missing ~/.gitconfig
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, ".gitignore_global"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.MCFS = fs
// setup root that contains user home, but missing excludesfile entry
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, gitconfigFile))
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, ".gitignore_global"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.MEFS = fs
// setup root that contains user home, but missing .gitnignore
fs = memfs.New()
err = fs.MkdirAll(home, os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(fs.Join(home, gitconfigFile))
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(" excludesfile = " + strconv.Quote(fs.Join(home, ".gitignore_global")) + "\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.MIFS = fs
// setup root that contains user home
fs = memfs.New()
err = fs.MkdirAll("etc", os.ModePerm)
c.Assert(err, IsNil)
f, err = fs.Create(systemFile)
c.Assert(err, IsNil)
_, err = f.Write([]byte("[core]\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(" excludesfile = /etc/gitignore_global\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
f, err = fs.Create("/etc/gitignore_global")
c.Assert(err, IsNil)
_, err = f.Write([]byte("# IntelliJ\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte(".idea/\n"))
c.Assert(err, IsNil)
_, err = f.Write([]byte("*.iml\n"))
c.Assert(err, IsNil)
err = f.Close()
c.Assert(err, IsNil)
s.SFS = fs
}
func (s *MatcherSuite) TestDir_ReadPatterns(c *C) {
checkPatterns := func(ps []Pattern) {
c.Assert(ps, HasLen, 7)
m := NewMatcher(ps)
c.Assert(m.Match([]string{"exclude.crlf"}, true), Equals, true)
c.Assert(m.Match([]string{"ignore.crlf"}, true), Equals, true)
c.Assert(m.Match([]string{"vendor", "gopkg.in"}, true), Equals, true)
c.Assert(m.Match([]string{"ignore_dir", "file"}, false), Equals, true)
c.Assert(m.Match([]string{"vendor", "github.com"}, true), Equals, false)
c.Assert(m.Match([]string{"multiple", "sub", "ignores", "first", "ignore_dir"}, true), Equals, true)
c.Assert(m.Match([]string{"multiple", "sub", "ignores", "second", "ignore_dir"}, true), Equals, true)
}
ps, err := ReadPatterns(s.GFS, nil)
c.Assert(err, IsNil)
checkPatterns(ps)
// passing an empty slice with capacity to check we don't hit a bug where the extra capacity is reused incorrectly
ps, err = ReadPatterns(s.GFS, make([]string, 0, 6))
c.Assert(err, IsNil)
checkPatterns(ps)
}
func (s *MatcherSuite) TestDir_ReadRelativeGlobalGitIgnore(c *C) {
for _, fs := range []billy.Filesystem{s.RFSR, s.RFSU} {
ps, err := LoadGlobalPatterns(fs)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 2)
m := NewMatcher(ps)
c.Assert(m.Match([]string{".idea/"}, true), Equals, false)
c.Assert(m.Match([]string{"*.iml"}, true), Equals, true)
c.Assert(m.Match([]string{"IntelliJ"}, true), Equals, false)
}
}
func (s *MatcherSuite) TestDir_LoadGlobalPatterns(c *C) {
ps, err := LoadGlobalPatterns(s.RFS)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 2)
m := NewMatcher(ps)
c.Assert(m.Match([]string{"go-git.v4.iml"}, true), Equals, true)
c.Assert(m.Match([]string{".idea"}, true), Equals, true)
}
func (s *MatcherSuite) TestDir_LoadGlobalPatternsMissingGitconfig(c *C) {
ps, err := LoadGlobalPatterns(s.MCFS)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 0)
}
func (s *MatcherSuite) TestDir_LoadGlobalPatternsMissingExcludesfile(c *C) {
ps, err := LoadGlobalPatterns(s.MEFS)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 0)
}
func (s *MatcherSuite) TestDir_LoadGlobalPatternsMissingGitignore(c *C) {
ps, err := LoadGlobalPatterns(s.MIFS)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 0)
}
func (s *MatcherSuite) TestDir_LoadSystemPatterns(c *C) {
ps, err := LoadSystemPatterns(s.SFS)
c.Assert(err, IsNil)
c.Assert(ps, HasLen, 2)
m := NewMatcher(ps)
c.Assert(m.Match([]string{"go-git.v4.iml"}, true), Equals, true)
c.Assert(m.Match([]string{".idea"}, true), Equals, true)
}