Skip to content

Commit 9d3e52d

Browse files
committed
git/gitattr: add support for parsing macros
In certain gitattributes files, it's possible to specify macros in addition to plain patterns. Add basic support for parsing these macros.
1 parent 28f9600 commit 9d3e52d

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

git/gitattr/attr.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/git-lfs/wildmatch"
1212
)
1313

14+
const attrPrefix = "[attr]"
15+
1416
// Line carries a single line from a repository's .gitattributes file, affecting
1517
// a single pattern and applying zero or more attributes.
1618
type Line struct {
@@ -22,6 +24,12 @@ type Line struct {
2224
// repository, while /path/to/.gitattributes affects all blobs that are
2325
// direct or indirect children of /path/to.
2426
Pattern *wildmatch.Wildmatch
27+
// Macro is the name of a macro that, when matched, indicates that all
28+
// of the below attributes (Attrs) should be applied to that tree
29+
// entry.
30+
//
31+
// A given entry will have exactly one of Pattern or Macro set.
32+
Macro string
2533
// Attrs is the list of attributes to be applied when the above pattern
2634
// matches a given filename.
2735
//
@@ -66,6 +74,7 @@ func ParseLines(r io.Reader) ([]*Line, string, error) {
6674

6775
var pattern string
6876
var applied string
77+
var macro string
6978

7079
switch text[0] {
7180
case '#':
@@ -84,7 +93,11 @@ func ParseLines(r io.Reader) ([]*Line, string, error) {
8493
default:
8594
splits := strings.SplitN(text, " ", 2)
8695

87-
pattern = splits[0]
96+
if strings.HasPrefix(splits[0], attrPrefix) {
97+
macro = splits[0][len(attrPrefix):]
98+
} else {
99+
pattern = splits[0]
100+
}
88101
if len(splits) == 2 {
89102
applied = splits[1]
90103
}
@@ -116,11 +129,17 @@ func ParseLines(r io.Reader) ([]*Line, string, error) {
116129
attrs = append(attrs, &attr)
117130
}
118131

119-
lines = append(lines, &Line{
120-
Pattern: wildmatch.NewWildmatch(pattern,
132+
var matchPattern *wildmatch.Wildmatch
133+
if pattern != "" {
134+
matchPattern = wildmatch.NewWildmatch(pattern,
121135
wildmatch.Basename, wildmatch.SystemCase,
122-
),
123-
Attrs: attrs,
136+
)
137+
}
138+
139+
lines = append(lines, &Line{
140+
Macro: macro,
141+
Pattern: matchPattern,
142+
Attrs: attrs,
124143
})
125144
}
126145

git/gitattr/attr_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,31 @@ func TestParseLinesWithNoAttributes(t *testing.T) {
138138
assert.Equal(t, lines[0].Pattern.String(), "*.dat")
139139
assert.Empty(t, lines[0].Attrs)
140140
}
141+
142+
func TestParseLinesWithMacros(t *testing.T) {
143+
lines, _, err := ParseLines(strings.NewReader(strings.Join([]string{
144+
"[attr]lfs filter=lfs diff=lfs merge=lfs -text",
145+
"*.dat lfs",
146+
"*.txt text"}, "\n")))
147+
148+
assert.Len(t, lines, 3)
149+
assert.NoError(t, err)
150+
151+
assert.Equal(t, lines[0].Macro, "lfs")
152+
assert.Nil(t, lines[0].Pattern)
153+
assert.Len(t, lines[0].Attrs, 4)
154+
assert.Equal(t, lines[0].Attrs[0], &Attr{K: "filter", V: "lfs"})
155+
assert.Equal(t, lines[0].Attrs[1], &Attr{K: "diff", V: "lfs"})
156+
assert.Equal(t, lines[0].Attrs[2], &Attr{K: "merge", V: "lfs"})
157+
assert.Equal(t, lines[0].Attrs[3], &Attr{K: "text", V: "false"})
158+
159+
assert.Equal(t, lines[1].Macro, "")
160+
assert.Equal(t, lines[1].Pattern.String(), "*.dat")
161+
assert.Len(t, lines[1].Attrs, 1)
162+
assert.Equal(t, lines[1].Attrs[0], &Attr{K: "lfs", V: "true"})
163+
164+
assert.Equal(t, lines[2].Macro, "")
165+
assert.Equal(t, lines[2].Pattern.String(), "*.txt")
166+
assert.Len(t, lines[2].Attrs, 1)
167+
assert.Equal(t, lines[2].Attrs[0], &Attr{K: "text", V: "true"})
168+
}

0 commit comments

Comments
 (0)