You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dir.go 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package gitignore
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "os"
  6. "os/user"
  7. "strings"
  8. "github.com/go-git/go-billy/v5"
  9. "github.com/go-git/go-git/v5/plumbing/format/config"
  10. gioutil "github.com/go-git/go-git/v5/utils/ioutil"
  11. )
  12. const (
  13. commentPrefix = "#"
  14. coreSection = "core"
  15. eol = "\n"
  16. excludesfile = "excludesfile"
  17. gitDir = ".git"
  18. gitignoreFile = ".gitignore"
  19. gitconfigFile = ".gitconfig"
  20. systemFile = "/etc/gitconfig"
  21. )
  22. // readIgnoreFile reads a specific git ignore file.
  23. func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps []Pattern, err error) {
  24. f, err := fs.Open(fs.Join(append(path, ignoreFile)...))
  25. if err == nil {
  26. defer f.Close()
  27. if data, err := ioutil.ReadAll(f); err == nil {
  28. for _, s := range strings.Split(string(data), eol) {
  29. if !strings.HasPrefix(s, commentPrefix) && len(strings.TrimSpace(s)) > 0 {
  30. ps = append(ps, ParsePattern(s, path))
  31. }
  32. }
  33. }
  34. } else if !os.IsNotExist(err) {
  35. return nil, err
  36. }
  37. return
  38. }
  39. // ReadPatterns reads gitignore patterns recursively traversing through the directory
  40. // structure. The result is in the ascending order of priority (last higher).
  41. func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error) {
  42. ps, _ = readIgnoreFile(fs, path, gitignoreFile)
  43. var fis []os.FileInfo
  44. fis, err = fs.ReadDir(fs.Join(path...))
  45. if err != nil {
  46. return
  47. }
  48. for _, fi := range fis {
  49. if fi.IsDir() && fi.Name() != gitDir {
  50. var subps []Pattern
  51. subps, err = ReadPatterns(fs, append(path, fi.Name()))
  52. if err != nil {
  53. return
  54. }
  55. if len(subps) > 0 {
  56. ps = append(ps, subps...)
  57. }
  58. }
  59. }
  60. return
  61. }
  62. func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) {
  63. f, err := fs.Open(path)
  64. if err != nil {
  65. if os.IsNotExist(err) {
  66. return nil, nil
  67. }
  68. return nil, err
  69. }
  70. defer gioutil.CheckClose(f, &err)
  71. b, err := ioutil.ReadAll(f)
  72. if err != nil {
  73. return
  74. }
  75. d := config.NewDecoder(bytes.NewBuffer(b))
  76. raw := config.New()
  77. if err = d.Decode(raw); err != nil {
  78. return
  79. }
  80. s := raw.Section(coreSection)
  81. efo := s.Options.Get(excludesfile)
  82. if efo == "" {
  83. return nil, nil
  84. }
  85. ps, err = readIgnoreFile(fs, nil, efo)
  86. if os.IsNotExist(err) {
  87. return nil, nil
  88. }
  89. return
  90. }
  91. // LoadGlobalPatterns loads gitignore patterns from from the gitignore file
  92. // declared in a user's ~/.gitconfig file. If the ~/.gitconfig file does not
  93. // exist the function will return nil. If the core.excludesfile property
  94. // is not declared, the function will return nil. If the file pointed to by
  95. // the core.excludesfile property does not exist, the function will return nil.
  96. //
  97. // The function assumes fs is rooted at the root filesystem.
  98. func LoadGlobalPatterns(fs billy.Filesystem) (ps []Pattern, err error) {
  99. usr, err := user.Current()
  100. if err != nil {
  101. return
  102. }
  103. return loadPatterns(fs, fs.Join(usr.HomeDir, gitconfigFile))
  104. }
  105. // LoadSystemPatterns loads gitignore patterns from from the gitignore file
  106. // declared in a system's /etc/gitconfig file. If the ~/.gitconfig file does
  107. // not exist the function will return nil. If the core.excludesfile property
  108. // is not declared, the function will return nil. If the file pointed to by
  109. // the core.excludesfile property does not exist, the function will return nil.
  110. //
  111. // The function assumes fs is rooted at the root filesystem.
  112. func LoadSystemPatterns(fs billy.Filesystem) (ps []Pattern, err error) {
  113. return loadPatterns(fs, systemFile)
  114. }