1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
package gitattributes
import (
"os"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-git/v5/plumbing/format/config"
gioutil "github.com/go-git/go-git/v5/utils/ioutil"
)
const (
coreSection = "core"
attributesfile = "attributesfile"
gitDir = ".git"
gitattributesFile = ".gitattributes"
gitconfigFile = ".gitconfig"
systemFile = "/etc/gitconfig"
)
func ReadAttributesFile(fs billy.Filesystem, path []string, attributesFile string, allowMacro bool) ([]MatchAttribute, error) {
f, err := fs.Open(fs.Join(append(path, attributesFile)...))
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, err
}
return ReadAttributes(f, path, allowMacro)
}
// ReadPatterns reads gitattributes patterns recursively through the directory
// structure. The result is in ascending order of priority (last higher).
//
// The .gitattribute file in the root directory will allow custom macro
// definitions. Custom macro definitions in other directories .gitattributes
// will return an error.
func ReadPatterns(fs billy.Filesystem, path []string) (attributes []MatchAttribute, err error) {
attributes, err = ReadAttributesFile(fs, path, gitattributesFile, true)
if err != nil {
return
}
attrs, err := walkDirectory(fs, path)
return append(attributes, attrs...), err
}
func walkDirectory(fs billy.Filesystem, root []string) (attributes []MatchAttribute, err error) {
fis, err := fs.ReadDir(fs.Join(root...))
if err != nil {
return attributes, err
}
for _, fi := range fis {
if !fi.IsDir() || fi.Name() == ".git" {
continue
}
path := append(root, fi.Name())
dirAttributes, err := ReadAttributesFile(fs, path, gitattributesFile, false)
if err != nil {
return attributes, err
}
subAttributes, err := walkDirectory(fs, path)
if err != nil {
return attributes, err
}
attributes = append(attributes, append(dirAttributes, subAttributes...)...)
}
return
}
func loadPatterns(fs billy.Filesystem, path string) ([]MatchAttribute, error) {
f, err := fs.Open(path)
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, err
}
defer gioutil.CheckClose(f, &err)
raw := config.New()
if err = config.NewDecoder(f).Decode(raw); err != nil {
return nil, nil
}
path = raw.Section(coreSection).Options.Get(attributesfile)
if path == "" {
return nil, nil
}
return ReadAttributesFile(fs, nil, path, true)
}
// LoadGlobalPatterns loads gitattributes patterns and attributes from the
// gitattributes file declared in a user's ~/.gitconfig file. If the
// ~/.gitconfig file does not exist the function will return nil. If the
// core.attributesFile property is not declared, the function will return nil.
// If the file pointed to by the core.attributesfile property does not exist,
// the function will return nil. The function assumes fs is rooted at the root
// filesystem.
func LoadGlobalPatterns(fs billy.Filesystem) (attributes []MatchAttribute, err error) {
home, err := os.UserHomeDir()
if err != nil {
return
}
return loadPatterns(fs, fs.Join(home, gitconfigFile))
}
// LoadSystemPatterns loads gitattributes patterns and attributes from the
// gitattributes file declared in a system's /etc/gitconfig file. If the
// /etc/gitconfig file does not exist the function will return nil. If the
// core.attributesfile property is not declared, the function will return nil.
// If the file pointed to by the core.attributesfile property does not exist,
// the function will return nil. The function assumes fs is rooted at the root
// filesystem.
func LoadSystemPatterns(fs billy.Filesystem) (attributes []MatchAttribute, err error) {
return loadPatterns(fs, systemFile)
}
|