Skip to content

Commit 9727b9b

Browse files
committed
utils: merkletrie, Apply autocrlf conversion on diff hash calculation
1 parent ae4a8de commit 9727b9b

4 files changed

Lines changed: 83 additions & 3 deletions

File tree

utils/merkletrie/filesystem/node.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package filesystem
22

33
import (
4+
"io"
45
"os"
56
"path"
67

78
"github.com/go-git/go-git/v6/plumbing"
89
"github.com/go-git/go-git/v6/plumbing/filemode"
910
format "github.com/go-git/go-git/v6/plumbing/format/config"
11+
"github.com/go-git/go-git/v6/utils/convert"
1012
"github.com/go-git/go-git/v6/utils/ioutil"
1113
"github.com/go-git/go-git/v6/utils/merkletrie/noder"
14+
"github.com/go-git/go-git/v6/utils/sync"
1215

1316
"github.com/go-git/go-billy/v6"
1417
)
@@ -17,6 +20,11 @@ var ignore = map[string]bool{
1720
".git": true,
1821
}
1922

23+
type Options struct {
24+
// AutoCRLF converts CRLF line endings in text files into LF line endings.
25+
AutoCRLF bool
26+
}
27+
2028
// The node represents a file or a directory in a billy.Filesystem. It
2129
// implements the interface noder.Noder of merkletrie package.
2230
//
@@ -26,6 +34,8 @@ type node struct {
2634
fs billy.Filesystem
2735
submodules map[string]plumbing.Hash
2836

37+
options *Options
38+
2939
path string
3040
hash []byte
3141
children []noder.Noder
@@ -46,6 +56,19 @@ func NewRootNode(
4656
return &node{fs: fs, submodules: submodules, isDir: true}
4757
}
4858

59+
func NewRootNodeWithOptions(
60+
fs billy.Filesystem,
61+
submodules map[string]plumbing.Hash,
62+
options Options,
63+
) noder.Noder {
64+
return &node{
65+
fs: fs,
66+
submodules: submodules,
67+
options: &options,
68+
isDir: true,
69+
}
70+
}
71+
4972
// Hash the hash of a filesystem is the result of concatenating the computed
5073
// plumbing.Hash of the file as a Blob and its plumbing.FileMode; that way the
5174
// difftree algorithm will detect changes in the contents of files and also in
@@ -134,6 +157,7 @@ func (n *node) newChildNode(file os.FileInfo) (*node, error) {
134157
node := &node{
135158
fs: n.fs,
136159
submodules: n.submodules,
160+
options: n.options,
137161

138162
path: path,
139163
isDir: file.IsDir(),
@@ -176,11 +200,31 @@ func (n *node) doCalculateHashForRegular() plumbing.Hash {
176200
if err != nil {
177201
return plumbing.ZeroHash
178202
}
179-
180203
defer f.Close()
181204

182205
h := plumbing.NewHasher(format.SHA1, plumbing.BlobObject, n.size)
183-
if _, err := ioutil.CopyBufferPool(h, f); err != nil {
206+
var dst io.Writer = h
207+
208+
if n.options != nil && n.options.AutoCRLF {
209+
br := sync.GetBufioReader(f)
210+
defer sync.PutBufioReader(br)
211+
212+
stat, err := convert.GetStat(br)
213+
if err != nil {
214+
return plumbing.ZeroHash
215+
}
216+
217+
if _, err := f.Seek(0, io.SeekStart); err != nil {
218+
return plumbing.ZeroHash
219+
}
220+
221+
if !stat.IsBinary() {
222+
h.Reset(plumbing.BlobObject, n.size-int64(stat.CRLF))
223+
dst = convert.NewLFWriter(dst)
224+
}
225+
}
226+
227+
if _, err := ioutil.CopyBufferPool(dst, f); err != nil {
184228
return plumbing.ZeroHash
185229
}
186230

utils/merkletrie/filesystem/node_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ func (s *NoderSuite) TestDiff() {
5151
s.Len(ch, 0)
5252
}
5353

54+
func (s *NoderSuite) TestDiffCRLF() {
55+
fsA := memfs.New()
56+
WriteFile(fsA, "foo", []byte("foo\n"), 0644)
57+
WriteFile(fsA, "qux/bar", []byte("foo\n"), 0644)
58+
WriteFile(fsA, "qux/qux", []byte("foo\n"), 0644)
59+
fsA.Symlink("foo", "bar")
60+
61+
fsB := memfs.New()
62+
WriteFile(fsB, "foo", []byte("foo\r\n"), 0644)
63+
WriteFile(fsB, "qux/bar", []byte("foo\r\n"), 0644)
64+
WriteFile(fsB, "qux/qux", []byte("foo\r\n"), 0644)
65+
fsB.Symlink("foo", "bar")
66+
67+
ch, err := merkletrie.DiffTree(
68+
NewRootNode(fsA, nil),
69+
NewRootNodeWithOptions(fsB, nil, Options{AutoCRLF: true}),
70+
IsEquals,
71+
)
72+
73+
s.NoError(err)
74+
s.Len(ch, 0)
75+
}
76+
5477
func (s *NoderSuite) TestDiffChangeLink() {
5578
fsA := memfs.New()
5679
fsA.Symlink("qux", "foo")

worktree_status.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,16 @@ func (w *Worktree) diffStagingWithWorktree(reverse, excludeIgnoredChanges bool)
143143
return nil, err
144144
}
145145

146-
to := filesystem.NewRootNode(w.Filesystem, submodules)
146+
cfg, err := w.r.Config()
147+
if err != nil {
148+
return nil, err
149+
}
150+
151+
fsOpts := filesystem.Options{
152+
AutoCRLF: cfg.Core.AutoCRLF == "true" || cfg.Core.AutoCRLF == "input",
153+
}
154+
155+
to := filesystem.NewRootNodeWithOptions(w.Filesystem, submodules, fsOpts)
147156

148157
var c merkletrie.Changes
149158
if reverse {

worktree_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ func (s *WorktreeSuite) TestCheckoutCRLF() {
509509

510510
require.NoError(t, wt.Checkout(&CheckoutOptions{}))
511511

512+
status, err := wt.Status()
513+
require.NoError(t, err)
514+
require.True(t, status.IsClean(), status)
515+
512516
file, err := wt.Filesystem.Open("CHANGELOG")
513517
require.NoError(t, err)
514518

0 commit comments

Comments
 (0)