@@ -12,6 +12,17 @@ import (
1212 "github.com/git-pkgs/archives"
1313)
1414
15+ const (
16+ // binaryCheckSize is the number of bytes to check for null bytes when
17+ // determining if content is binary.
18+ binaryCheckSize = 8192
19+
20+ // Diff type constants for FileDiff.Type.
21+ TypeModified = "modified"
22+ TypeAdded = "added"
23+ TypeDeleted = "deleted"
24+ )
25+
1526// FileDiff represents the diff for a single file.
1627type FileDiff struct {
1728 Path string `json:"path"`
@@ -87,67 +98,71 @@ func Compare(oldReader, newReader archives.Reader) (*CompareResult, error) {
8798 oldExists := oldMap [path ]
8899 newExists := newMap [path ]
89100
90- var fileDiff FileDiff
101+ fileDiff , ok := compareFile (path , oldExists , newExists , oldReader , newReader )
102+ if ! ok {
103+ continue
104+ }
91105
92- if oldExists .Path != "" && newExists .Path == "" {
93- // File was deleted
94- fileDiff = FileDiff {
95- Path : path ,
96- Type : "deleted" ,
97- }
106+ switch fileDiff .Type {
107+ case TypeDeleted :
98108 result .FilesDeleted ++
99- } else if oldExists .Path == "" && newExists .Path != "" {
100- // File was added
101- fileDiff = FileDiff {
102- Path : path ,
103- Type : "added" ,
104- }
109+ case TypeAdded :
105110 result .FilesAdded ++
111+ case TypeModified :
112+ result .FilesChanged ++
113+ result .TotalAdded += fileDiff .LinesAdded
114+ result .TotalDeleted += fileDiff .LinesDeleted
115+ }
106116
107- // Try to get content for added files
108- if content , err := readFileContent (newReader , path ); err == nil {
109- if isBinary (content ) {
110- fileDiff .IsBinary = true
111- } else {
112- fileDiff .Diff = generateAddedDiff (path , content )
113- fileDiff .LinesAdded = countLines (content )
114- }
115- }
116- } else {
117- // File exists in both - check if modified
118- oldContent , err1 := readFileContent (oldReader , path )
119- newContent , err2 := readFileContent (newReader , path )
120-
121- if err1 != nil || err2 != nil {
122- continue // Skip files we can't read
123- }
124-
125- if bytes .Equal (oldContent , newContent ) {
126- continue // No change
127- }
117+ result .Files = append (result .Files , fileDiff )
118+ }
128119
129- fileDiff = FileDiff {
130- Path : path ,
131- Type : "modified" ,
132- }
133- result .FilesChanged ++
120+ return result , nil
121+ }
134122
135- if isBinary (oldContent ) || isBinary (newContent ) {
136- fileDiff .IsBinary = true
123+ // compareFile compares a single file between old and new archives.
124+ // Returns the diff and false if the file should be skipped.
125+ func compareFile (path string , oldInfo , newInfo archives.FileInfo , oldReader , newReader archives.Reader ) (FileDiff , bool ) {
126+ inOld := oldInfo .Path != ""
127+ inNew := newInfo .Path != ""
128+
129+ switch {
130+ case inOld && ! inNew :
131+ return FileDiff {Path : path , Type : TypeDeleted }, true
132+
133+ case ! inOld && inNew :
134+ fd := FileDiff {Path : path , Type : TypeAdded }
135+ if content , err := readFileContent (newReader , path ); err == nil {
136+ if isBinary (content ) {
137+ fd .IsBinary = true
137138 } else {
138- diffText , added , deleted := generateUnifiedDiff (path , oldContent , newContent )
139- fileDiff .Diff = diffText
140- fileDiff .LinesAdded = added
141- fileDiff .LinesDeleted = deleted
142- result .TotalAdded += added
143- result .TotalDeleted += deleted
139+ fd .Diff = generateAddedDiff (path , content )
140+ fd .LinesAdded = countLines (content )
144141 }
145142 }
143+ return fd , true
146144
147- result .Files = append (result .Files , fileDiff )
148- }
145+ default :
146+ oldContent , err1 := readFileContent (oldReader , path )
147+ newContent , err2 := readFileContent (newReader , path )
148+ if err1 != nil || err2 != nil {
149+ return FileDiff {}, false
150+ }
151+ if bytes .Equal (oldContent , newContent ) {
152+ return FileDiff {}, false
153+ }
149154
150- return result , nil
155+ fd := FileDiff {Path : path , Type : TypeModified }
156+ if isBinary (oldContent ) || isBinary (newContent ) {
157+ fd .IsBinary = true
158+ } else {
159+ diffText , added , deleted := generateUnifiedDiff (path , oldContent , newContent )
160+ fd .Diff = diffText
161+ fd .LinesAdded = added
162+ fd .LinesDeleted = deleted
163+ }
164+ return fd , true
165+ }
151166}
152167
153168// readFileContent reads a file's content from an archive reader.
@@ -169,8 +184,8 @@ func isBinary(content []byte) bool {
169184
170185 // Check first 8KB for null bytes
171186 checkLen := len (content )
172- if checkLen > 8192 {
173- checkLen = 8192
187+ if checkLen > binaryCheckSize {
188+ checkLen = binaryCheckSize
174189 }
175190
176191 for i := 0 ; i < checkLen ; i ++ {
0 commit comments