summaryrefslogtreecommitdiffstats
path: root/services/gitdiff/gitdiff.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-02-27 18:46:14 +0000
committerGitHub <noreply@github.com>2021-02-27 19:46:14 +0100
commit3d8b5ad5f37f495e50d83bbad214f8061f8a5ac4 (patch)
treec4fb9d7b195f9a7af5d2e3fc275fa74accf0d01c /services/gitdiff/gitdiff.go
parent904a26c57c474e0ed7b43dc37269f69b49240301 (diff)
downloadgitea-3d8b5ad5f37f495e50d83bbad214f8061f8a5ac4.tar.gz
gitea-3d8b5ad5f37f495e50d83bbad214f8061f8a5ac4.zip
Fix a couple of CommentAsPatch issues. (#14804)
* CutDiffAroundLine makes the incorrect assumption that `---` and `+++` always represent part of the header of a diff. This PR adds a flag to its parsing to prevent this problem and adds a streaming parsing technique to CutDiffAroundLine using an io.pipe instead of just sending data to an unbounded buffer. Fix #14711 Signed-off-by: Andrew Thornton <art27@cantab.net> * Handle unquoted comment patch files When making comment patches unfortunately the patch does not always quote the filename This makes the diff --git header ambiguous again. This PR finally adds handling for ambiguity in to parse patch Fix #14812 Signed-off-by: Andrew Thornton <art27@cantab.net> * Add in testing for no error There is no way currently for CutDiffAroundLine in this test to cause an error however, it should still be tested. Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'services/gitdiff/gitdiff.go')
-rw-r--r--services/gitdiff/gitdiff.go95
1 files changed, 89 insertions, 6 deletions
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index d5c3923516..9f038c8744 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -583,6 +583,7 @@ type DiffFile struct {
IsBin bool
IsLFSFile bool
IsRenamed bool
+ IsAmbiguous bool
IsSubmodule bool
Sections []*DiffSection
IsIncomplete bool
@@ -776,12 +777,32 @@ parsingLoop:
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
+ case strings.HasPrefix(line, "rename from "):
+ curFile.IsRenamed = true
+ curFile.Type = DiffFileRename
+ if curFile.IsAmbiguous {
+ curFile.OldName = line[len("rename from ") : len(line)-1]
+ }
+ case strings.HasPrefix(line, "rename to "):
+ curFile.IsRenamed = true
+ curFile.Type = DiffFileRename
+ if curFile.IsAmbiguous {
+ curFile.Name = line[len("rename to ") : len(line)-1]
+ curFile.IsAmbiguous = false
+ }
case strings.HasPrefix(line, "copy from "):
curFile.IsRenamed = true
curFile.Type = DiffFileCopy
+ if curFile.IsAmbiguous {
+ curFile.OldName = line[len("copy from ") : len(line)-1]
+ }
case strings.HasPrefix(line, "copy to "):
curFile.IsRenamed = true
curFile.Type = DiffFileCopy
+ if curFile.IsAmbiguous {
+ curFile.Name = line[len("copy to ") : len(line)-1]
+ curFile.IsAmbiguous = false
+ }
case strings.HasPrefix(line, "new file"):
curFile.Type = DiffFileAdd
curFile.IsCreated = true
@@ -803,9 +824,35 @@ parsingLoop:
case strings.HasPrefix(line, "Binary"):
curFile.IsBin = true
case strings.HasPrefix(line, "--- "):
- // Do nothing with this line
+ // Handle ambiguous filenames
+ if curFile.IsAmbiguous {
+ if len(line) > 6 && line[4] == 'a' {
+ curFile.OldName = line[6 : len(line)-1]
+ if line[len(line)-2] == '\t' {
+ curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
+ }
+ } else {
+ curFile.OldName = ""
+ }
+ }
+ // Otherwise do nothing with this line
case strings.HasPrefix(line, "+++ "):
- // Do nothing with this line
+ // Handle ambiguous filenames
+ if curFile.IsAmbiguous {
+ if len(line) > 6 && line[4] == 'b' {
+ curFile.Name = line[6 : len(line)-1]
+ if line[len(line)-2] == '\t' {
+ curFile.Name = curFile.Name[:len(curFile.Name)-1]
+ }
+ if curFile.OldName == "" {
+ curFile.OldName = curFile.Name
+ }
+ } else {
+ curFile.Name = curFile.OldName
+ }
+ curFile.IsAmbiguous = false
+ }
+ // Otherwise do nothing with this line, but now switch to parsing hunks
lineBytes, isFragment, err := parseHunks(curFile, maxLines, maxLineCharacters, input)
diff.TotalAddition += curFile.Addition
diff.TotalDeletion += curFile.Deletion
@@ -1056,13 +1103,33 @@ func createDiffFile(diff *Diff, line string) *DiffFile {
rd := strings.NewReader(line[len(cmdDiffHead):] + " ")
curFile.Type = DiffFileChange
- curFile.OldName = readFileName(rd)
- curFile.Name = readFileName(rd)
+ oldNameAmbiguity := false
+ newNameAmbiguity := false
+
+ curFile.OldName, oldNameAmbiguity = readFileName(rd)
+ curFile.Name, newNameAmbiguity = readFileName(rd)
+ if oldNameAmbiguity && newNameAmbiguity {
+ curFile.IsAmbiguous = true
+ // OK we should bet that the oldName and the newName are the same if they can be made to be same
+ // So we need to start again ...
+ if (len(line)-len(cmdDiffHead)-1)%2 == 0 {
+ // diff --git a/b b/b b/b b/b b/b b/b
+ //
+ midpoint := (len(line) + len(cmdDiffHead) - 1) / 2
+ new, old := line[len(cmdDiffHead):midpoint], line[midpoint+1:]
+ if len(new) > 2 && len(old) > 2 && new[2:] == old[2:] {
+ curFile.OldName = old[2:]
+ curFile.Name = old[2:]
+ }
+ }
+ }
+
curFile.IsRenamed = curFile.Name != curFile.OldName
return curFile
}
-func readFileName(rd *strings.Reader) string {
+func readFileName(rd *strings.Reader) (string, bool) {
+ ambiguity := false
var name string
char, _ := rd.ReadByte()
_ = rd.UnreadByte()
@@ -1072,9 +1139,24 @@ func readFileName(rd *strings.Reader) string {
name = name[1:]
}
} else {
+ // This technique is potentially ambiguous it may not be possible to uniquely identify the filenames from the diff line alone
+ ambiguity = true
fmt.Fscanf(rd, "%s ", &name)
+ char, _ := rd.ReadByte()
+ _ = rd.UnreadByte()
+ for !(char == 0 || char == '"' || char == 'b') {
+ var suffix string
+ fmt.Fscanf(rd, "%s ", &suffix)
+ name += " " + suffix
+ char, _ = rd.ReadByte()
+ _ = rd.UnreadByte()
+ }
+ }
+ if len(name) < 2 {
+ log.Error("Unable to determine name from reader: %v", rd)
+ return "", true
}
- return name[2:]
+ return name[2:], ambiguity
}
// GetDiffRange builds a Diff between two commits of a repository.
@@ -1191,6 +1273,7 @@ func CommentAsDiff(c *models.Comment) (*Diff, error) {
diff, err := ParsePatch(setting.Git.MaxGitDiffLines,
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch))
if err != nil {
+ log.Error("Unable to parse patch: %v", err)
return nil, err
}
if len(diff.Files) == 0 {