diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2019-04-24 14:38:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-24 14:38:25 +0200 |
commit | bbca4e0ccc8fee164e6da28edebbd76d69cdfd9b (patch) | |
tree | a7a3f9fb8d84ea78b002be45c7380080fe21025d /plumbing/format/gitattributes/matcher.go | |
parent | 4a6229296f5d8991d46e581d331e4e889a5a87ec (diff) | |
parent | 86bdbfbf45a0c13aca146955a3325207ebd66c75 (diff) | |
download | go-git-bbca4e0ccc8fee164e6da28edebbd76d69cdfd9b.tar.gz |
Merge pull request #1130 from saracen/gitattributes
plumbing: format/gitattributes support
Diffstat (limited to 'plumbing/format/gitattributes/matcher.go')
-rw-r--r-- | plumbing/format/gitattributes/matcher.go | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/plumbing/format/gitattributes/matcher.go b/plumbing/format/gitattributes/matcher.go new file mode 100644 index 0000000..df12864 --- /dev/null +++ b/plumbing/format/gitattributes/matcher.go @@ -0,0 +1,78 @@ +package gitattributes + +// Matcher defines a global multi-pattern matcher for gitattributes patterns +type Matcher interface { + // Match matches patterns in the order of priorities. + Match(path []string, attributes []string) (map[string]Attribute, bool) +} + +type MatcherOptions struct{} + +// NewMatcher constructs a new matcher. Patterns must be given in the order of +// increasing priority. That is the most generic settings files first, then the +// content of the repo .gitattributes, then content of .gitattributes down the +// path. +func NewMatcher(stack []MatchAttribute) Matcher { + m := &matcher{stack: stack} + m.init() + + return m +} + +type matcher struct { + stack []MatchAttribute + macros map[string]MatchAttribute +} + +func (m *matcher) init() { + m.macros = make(map[string]MatchAttribute) + + for _, attr := range m.stack { + if attr.Pattern == nil { + m.macros[attr.Name] = attr + } + } +} + +// Match matches path against the patterns in gitattributes files and returns +// the attributes associated with the path. +// +// Specific attributes can be specified otherwise all attributes are returned. +// +// Matched is true if any path was matched to a rule, even if the results map +// is empty. +func (m *matcher) Match(path []string, attributes []string) (results map[string]Attribute, matched bool) { + results = make(map[string]Attribute, len(attributes)) + + n := len(m.stack) + for i := n - 1; i >= 0; i-- { + if len(attributes) > 0 && len(attributes) == len(results) { + return + } + + pattern := m.stack[i].Pattern + if pattern == nil { + continue + } + + if match := pattern.Match(path); match { + matched = true + for _, attr := range m.stack[i].Attributes { + if attr.IsSet() { + m.expandMacro(attr.Name(), results) + } + results[attr.Name()] = attr + } + } + } + return +} + +func (m *matcher) expandMacro(name string, results map[string]Attribute) bool { + if macro, ok := m.macros[name]; ok { + for _, attr := range macro.Attributes { + results[attr.Name()] = attr + } + } + return false +} |