@@ -694,9 +694,11 @@ func (diff *Diff) LoadComments(issue *models.Issue, currentUser *models.User) er
694
694
const cmdDiffHead = "diff --git "
695
695
696
696
// ParsePatch builds a Diff object from a io.Reader and some parameters.
697
- func ParsePatch (maxLines , maxLineCharacters , maxFiles int , reader io.Reader ) (* Diff , error ) {
697
+ func ParsePatch (maxLines , maxLineCharacters , maxFiles int , reader io.Reader , skipToFile string ) (* Diff , error ) {
698
698
var curFile * DiffFile
699
699
700
+ skipping := skipToFile != ""
701
+
700
702
diff := & Diff {Files : make ([]* DiffFile , 0 )}
701
703
702
704
sb := strings.Builder {}
@@ -721,24 +723,36 @@ parsingLoop:
721
723
// 1. A patch file always begins with `diff --git ` + `a/path b/path` (possibly quoted)
722
724
// if it does not we have bad input!
723
725
if ! strings .HasPrefix (line , cmdDiffHead ) {
724
- return diff , fmt .Errorf ("Invalid first file line: %s" , line )
726
+ return diff , fmt .Errorf ("invalid first file line: %s" , line )
725
727
}
726
728
727
- // TODO: Handle skipping first n files
728
729
if len (diff .Files ) >= maxFiles {
729
-
730
730
lastFile := createDiffFile (diff , line )
731
731
diff .End = lastFile .Name
732
732
diff .IsIncomplete = true
733
733
_ , err := io .Copy (io .Discard , reader )
734
734
if err != nil {
735
735
// By the definition of io.Copy this never returns io.EOF
736
- return diff , fmt .Errorf ("Copy: %v " , err )
736
+ return diff , fmt .Errorf ("error during io. Copy: %w " , err )
737
737
}
738
738
break parsingLoop
739
739
}
740
740
741
741
curFile = createDiffFile (diff , line )
742
+ if skipping {
743
+ if curFile .Name != skipToFile {
744
+ line , err = skipToNextDiffHead (input )
745
+ if err != nil {
746
+ if err == io .EOF {
747
+ return diff , nil
748
+ }
749
+ return diff , err
750
+ }
751
+ continue
752
+ }
753
+ skipping = false
754
+ }
755
+
742
756
diff .Files = append (diff .Files , curFile )
743
757
744
758
// 2. It is followed by one or more extended header lines:
@@ -892,7 +906,7 @@ parsingLoop:
892
906
lineBytes , isFragment , err = input .ReadLine ()
893
907
if err != nil {
894
908
// Now by the definition of ReadLine this cannot be io.EOF
895
- return diff , fmt .Errorf ("Unable to ReadLine: %v " , err )
909
+ return diff , fmt .Errorf ("unable to ReadLine: %w " , err )
896
910
}
897
911
_ , _ = sb .Write (lineBytes )
898
912
}
@@ -955,6 +969,36 @@ parsingLoop:
955
969
return diff , nil
956
970
}
957
971
972
+ func skipToNextDiffHead (input * bufio.Reader ) (line string , err error ) {
973
+ // need to skip until the next cmdDiffHead
974
+ isFragment , wasFragment := false , false
975
+ var lineBytes []byte
976
+ for {
977
+ lineBytes , isFragment , err = input .ReadLine ()
978
+ if err != nil {
979
+ return
980
+ }
981
+ if wasFragment {
982
+ wasFragment = isFragment
983
+ continue
984
+ }
985
+ if bytes .HasPrefix (lineBytes , []byte (cmdDiffHead )) {
986
+ break
987
+ }
988
+ wasFragment = isFragment
989
+ }
990
+ line = string (lineBytes )
991
+ if isFragment {
992
+ var tail string
993
+ tail , err = input .ReadString ('\n' )
994
+ if err != nil {
995
+ return
996
+ }
997
+ line += tail
998
+ }
999
+ return
1000
+ }
1001
+
958
1002
func parseHunks (curFile * DiffFile , maxLines , maxLineCharacters int , input * bufio.Reader ) (lineBytes []byte , isFragment bool , err error ) {
959
1003
sb := strings.Builder {}
960
1004
@@ -974,7 +1018,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
974
1018
_ , isFragment , err = input .ReadLine ()
975
1019
if err != nil {
976
1020
// Now by the definition of ReadLine this cannot be io.EOF
977
- err = fmt .Errorf ("Unable to ReadLine: %v " , err )
1021
+ err = fmt .Errorf ("unable to ReadLine: %w " , err )
978
1022
return
979
1023
}
980
1024
}
@@ -984,7 +1028,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
984
1028
if err == io .EOF {
985
1029
return
986
1030
}
987
- err = fmt .Errorf ("Unable to ReadLine: %v " , err )
1031
+ err = fmt .Errorf ("unable to ReadLine: %w " , err )
988
1032
return
989
1033
}
990
1034
if lineBytes [0 ] == 'd' {
@@ -1006,7 +1050,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1006
1050
lineBytes , isFragment , err = input .ReadLine ()
1007
1051
if err != nil {
1008
1052
// Now by the definition of ReadLine this cannot be io.EOF
1009
- err = fmt .Errorf ("Unable to ReadLine: %v " , err )
1053
+ err = fmt .Errorf ("unable to ReadLine: %w " , err )
1010
1054
return
1011
1055
}
1012
1056
_ , _ = sb .Write (lineBytes )
@@ -1037,7 +1081,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1037
1081
}
1038
1082
// This is used only to indicate that the current file does not have a terminal newline
1039
1083
if ! bytes .Equal (lineBytes , []byte ("\\ No newline at end of file" )) {
1040
- err = fmt .Errorf ("Unexpected line in hunk: %s" , string (lineBytes ))
1084
+ err = fmt .Errorf ("unexpected line in hunk: %s" , string (lineBytes ))
1041
1085
return
1042
1086
}
1043
1087
// Technically this should be the end the file!
@@ -1106,7 +1150,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1106
1150
curSection .Lines = append (curSection .Lines , diffLine )
1107
1151
default :
1108
1152
// This is unexpected
1109
- err = fmt .Errorf ("Unexpected line in hunk: %s" , string (lineBytes ))
1153
+ err = fmt .Errorf ("unexpected line in hunk: %s" , string (lineBytes ))
1110
1154
return
1111
1155
}
1112
1156
@@ -1118,7 +1162,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1118
1162
lineBytes , isFragment , err = input .ReadLine ()
1119
1163
if err != nil {
1120
1164
// Now by the definition of ReadLine this cannot be io.EOF
1121
- err = fmt .Errorf ("Unable to ReadLine: %v " , err )
1165
+ err = fmt .Errorf ("unable to ReadLine: %w " , err )
1122
1166
return
1123
1167
}
1124
1168
}
@@ -1279,8 +1323,14 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1279
1323
diffArgs = append (diffArgs , afterCommitID )
1280
1324
beforeCommitID = actualBeforeCommitID
1281
1325
}
1282
- if skipTo != "" {
1326
+
1327
+ // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
1328
+ // so if we are using at least this version of git we don't have to tell ParsePatch to do
1329
+ // the skipping for us
1330
+ parsePatchSkipToFile := skipTo
1331
+ if skipTo != "" && git .CheckGitVersionAtLeast ("2.31" ) == nil {
1283
1332
diffArgs = append (diffArgs , "--skip-to=" + skipTo )
1333
+ parsePatchSkipToFile = ""
1284
1334
}
1285
1335
cmd := exec .CommandContext (ctx , git .GitExecutable , diffArgs ... )
1286
1336
@@ -1289,19 +1339,19 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1289
1339
1290
1340
stdout , err := cmd .StdoutPipe ()
1291
1341
if err != nil {
1292
- return nil , fmt .Errorf ("StdoutPipe: %v " , err )
1342
+ return nil , fmt .Errorf ("error creating StdoutPipe: %w " , err )
1293
1343
}
1294
1344
1295
1345
if err = cmd .Start (); err != nil {
1296
- return nil , fmt .Errorf ("Start: %v " , err )
1346
+ return nil , fmt .Errorf ("error during Start: %w " , err )
1297
1347
}
1298
1348
1299
1349
pid := process .GetManager ().Add (fmt .Sprintf ("GetDiffRange [repo_path: %s]" , repoPath ), cancel )
1300
1350
defer process .GetManager ().Remove (pid )
1301
1351
1302
- diff , err := ParsePatch (maxLines , maxLineCharacters , maxFiles , stdout )
1352
+ diff , err := ParsePatch (maxLines , maxLineCharacters , maxFiles , stdout , parsePatchSkipToFile )
1303
1353
if err != nil {
1304
- return nil , fmt .Errorf ("ParsePatch: %v " , err )
1354
+ return nil , fmt .Errorf ("unable to ParsePatch: %w " , err )
1305
1355
}
1306
1356
diff .Start = skipTo
1307
1357
@@ -1383,7 +1433,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1383
1433
}
1384
1434
1385
1435
if err = cmd .Wait (); err != nil {
1386
- return nil , fmt .Errorf ("Wait: %v " , err )
1436
+ return nil , fmt .Errorf ("error during cmd. Wait: %w " , err )
1387
1437
}
1388
1438
1389
1439
separator := "..."
@@ -1418,7 +1468,7 @@ func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skip
1418
1468
// CommentAsDiff returns c.Patch as *Diff
1419
1469
func CommentAsDiff (c * models.Comment ) (* Diff , error ) {
1420
1470
diff , err := ParsePatch (setting .Git .MaxGitDiffLines ,
1421
- setting .Git .MaxGitDiffLineCharacters , setting .Git .MaxGitDiffFiles , strings .NewReader (c .Patch ))
1471
+ setting .Git .MaxGitDiffLineCharacters , setting .Git .MaxGitDiffFiles , strings .NewReader (c .Patch ), "" )
1422
1472
if err != nil {
1423
1473
log .Error ("Unable to parse patch: %v" , err )
1424
1474
return nil , err
0 commit comments