Skip to content

Commit f4b8938

Browse files
committed
git: expand macros when reading gitattributes files
Read and expand macros when reading the gitattributes files so that users can use shorthands such as "lfs" for "filter=lfs diff=lfs merge=lfs". Pass the same macro processor into each attribute lookup function, since macros can be defined in the system or global file and then used in per-repository files.
1 parent bef2aa5 commit f4b8938

File tree

4 files changed

+58
-13
lines changed

4 files changed

+58
-13
lines changed

commands/command_track.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"github.com/git-lfs/git-lfs/git"
14+
"github.com/git-lfs/git-lfs/git/gitattr"
1415
"github.com/git-lfs/git-lfs/tools"
1516
"github.com/spf13/cobra"
1617
)
@@ -50,9 +51,11 @@ func trackCommand(cmd *cobra.Command, args []string) {
5051
return
5152
}
5253

54+
mp := gitattr.NewMacroProcessor()
55+
5356
// Intentionally do _not_ consider global- and system-level
5457
// .gitattributes here.
55-
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
58+
knownPatterns := git.GetAttributePaths(mp, cfg.LocalWorkingDir(), cfg.LocalGitDir())
5659
lineEnd := getAttributeLineEnding(knownPatterns)
5760
if len(lineEnd) == 0 {
5861
lineEnd = gitLineEnding(cfg.Git)
@@ -243,9 +246,10 @@ func listPatterns() {
243246
}
244247

245248
func getAllKnownPatterns() []git.AttributePath {
246-
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
247-
knownPatterns = append(knownPatterns, git.GetRootAttributePaths(cfg.Git)...)
248-
knownPatterns = append(knownPatterns, git.GetSystemAttributePaths(cfg.Os)...)
249+
mp := gitattr.NewMacroProcessor()
250+
knownPatterns := git.GetAttributePaths(mp, cfg.LocalWorkingDir(), cfg.LocalGitDir())
251+
knownPatterns = append(knownPatterns, git.GetRootAttributePaths(mp, cfg.Git)...)
252+
knownPatterns = append(knownPatterns, git.GetSystemAttributePaths(mp, cfg.Os)...)
249253

250254
return knownPatterns
251255
}

git/attribs.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,20 @@ func (s *AttributeSource) String() string {
4343

4444
// GetRootAttributePaths beahves as GetRootAttributePaths, and loads information
4545
// only from the global gitattributes file.
46-
func GetRootAttributePaths(cfg Env) []AttributePath {
46+
func GetRootAttributePaths(mp *gitattr.MacroProcessor, cfg Env) []AttributePath {
4747
af, ok := cfg.Get("core.attributesfile")
4848
if !ok {
4949
return nil
5050
}
5151

5252
// The working directory for the root gitattributes file is blank.
53-
return attrPaths(af, "")
53+
return attrPaths(mp, af, "", true)
5454
}
5555

5656
// GetSystemAttributePaths behaves as GetAttributePaths, and loads information
5757
// only from the system gitattributes file, respecting the $PREFIX environment
5858
// variable.
59-
func GetSystemAttributePaths(env Env) []AttributePath {
59+
func GetSystemAttributePaths(mp *gitattr.MacroProcessor, env Env) []AttributePath {
6060
prefix, _ := env.Get("PREFIX")
6161
if len(prefix) == 0 {
6262
prefix = string(filepath.Separator)
@@ -68,24 +68,24 @@ func GetSystemAttributePaths(env Env) []AttributePath {
6868
return nil
6969
}
7070

71-
return attrPaths(path, "")
71+
return attrPaths(mp, path, "", true)
7272
}
7373

7474
// GetAttributePaths returns a list of entries in .gitattributes which are
7575
// configured with the filter=lfs attribute
7676
// workingDir is the root of the working copy
7777
// gitDir is the root of the git repo
78-
func GetAttributePaths(workingDir, gitDir string) []AttributePath {
78+
func GetAttributePaths(mp *gitattr.MacroProcessor, workingDir, gitDir string) []AttributePath {
7979
paths := make([]AttributePath, 0)
8080

8181
for _, file := range findAttributeFiles(workingDir, gitDir) {
82-
paths = append(paths, attrPaths(file.path, workingDir)...)
82+
paths = append(paths, attrPaths(mp, file.path, workingDir, file.readMacros)...)
8383
}
8484

8585
return paths
8686
}
8787

88-
func attrPaths(path, workingDir string) []AttributePath {
88+
func attrPaths(mp *gitattr.MacroProcessor, path, workingDir string, readMacros bool) []AttributePath {
8989
attributes, err := os.Open(path)
9090
if err != nil {
9191
return nil
@@ -103,6 +103,8 @@ func attrPaths(path, workingDir string) []AttributePath {
103103
return nil
104104
}
105105

106+
lines = mp.ProcessLines(lines, readMacros)
107+
106108
for _, line := range lines {
107109
lockable := false
108110
tracked := false
@@ -145,7 +147,7 @@ func attrPaths(path, workingDir string) []AttributePath {
145147
// workingDir is the root of the working copy
146148
// gitDir is the root of the git repo
147149
func GetAttributeFilter(workingDir, gitDir string) *filepathfilter.Filter {
148-
paths := GetAttributePaths(workingDir, gitDir)
150+
paths := GetAttributePaths(gitattr.NewMacroProcessor(), workingDir, gitDir)
149151
patterns := make([]filepathfilter.Pattern, 0, len(paths))
150152

151153
for _, path := range paths {

locking/lockable.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/git-lfs/git-lfs/errors"
1111
"github.com/git-lfs/git-lfs/filepathfilter"
1212
"github.com/git-lfs/git-lfs/git"
13+
"github.com/git-lfs/git-lfs/git/gitattr"
1314
"github.com/git-lfs/git-lfs/tools"
1415
)
1516

@@ -39,7 +40,7 @@ func (c *Client) ensureLockablesLoaded() {
3940
// Internal function to repopulate lockable patterns
4041
// You must have locked the c.lockableMutex in the caller
4142
func (c *Client) refreshLockablePatterns() {
42-
paths := git.GetAttributePaths(c.LocalWorkingDir, c.LocalGitDir)
43+
paths := git.GetAttributePaths(gitattr.NewMacroProcessor(), c.LocalWorkingDir, c.LocalGitDir)
4344
// Always make non-nil even if empty
4445
c.lockablePatterns = make([]string, 0, len(paths))
4546
for _, p := range paths {

t/t-attributes.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
3+
. "$(dirname "$0")/testlib.sh"
4+
5+
begin_test "macros"
6+
(
7+
set -e
8+
9+
reponame="$(basename "$0" ".sh")"
10+
clone_repo "$reponame" repo
11+
12+
mkdir dir
13+
printf '[attr]lfs filter=lfs diff=lfs merge=lfs -text\n*.dat lfs\n' \
14+
> .gitattributes
15+
printf '[attr]lfs2 filter=lfs diff=lfs merge=lfs -text\n*.bin lfs2\n' \
16+
> dir/.gitattributes
17+
git add .gitattributes dir
18+
git commit -m 'initial import'
19+
20+
contents="some data"
21+
printf "$contents" > foo.dat
22+
git add *.dat
23+
git commit -m 'foo.dat'
24+
assert_local_object "$(calc_oid "$contents")" 9
25+
26+
contents2="other data"
27+
printf "$contents2" > dir/foo.bin
28+
git add dir
29+
git commit -m 'foo.bin'
30+
refute_local_object "$(calc_oid "$contents2")"
31+
32+
git lfs track '*.dat' 2>&1 | tee track.log
33+
grep '"*.dat" already supported' track.log
34+
35+
git lfs track 'dir/*.bin' 2>&1 | tee track.log
36+
! grep '"dir/*.bin" already supported' track.log
37+
)
38+
end_test

0 commit comments

Comments
 (0)