diff options
author | Filip Navara <filip.navara@gmail.com> | 2019-04-26 10:07:59 +0200 |
---|---|---|
committer | Filip Navara <filip.navara@gmail.com> | 2019-04-26 10:07:59 +0200 |
commit | 14c17dc6881fccf851c8bdffab15774faa3bce8b (patch) | |
tree | e4e567231fee000bf6a6424577c60ce907431a18 /plumbing/format/gitattributes/matcher.go | |
parent | 34cb7a3aededd002881504dd729527628e923fc6 (diff) | |
parent | ca5d7bb1a790303d2ca245cb6225850bcf5d12a6 (diff) | |
download | go-git-14c17dc6881fccf851c8bdffab15774faa3bce8b.tar.gz |
Merge branch 'master' into commitgraph-obj
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 +} |