11package filesystem
22
33import (
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
0 commit comments