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