Add new algo to generate diff for line range
Remove old algo used for cutting big diffs (it was very buggy)
This commit is contained in:
parent
73b325c5d8
commit
3cd5ee4e42
|
@ -14,6 +14,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -258,6 +259,128 @@ func (diff *Diff) NumFiles() int {
|
|||
return len(diff.Files)
|
||||
}
|
||||
|
||||
// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
|
||||
var hunkRegex = regexp.MustCompile(`^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@`)
|
||||
|
||||
func isHeader(lof string) bool {
|
||||
return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++")
|
||||
}
|
||||
|
||||
func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) string {
|
||||
if line == 0 || numbersOfLine == 0 {
|
||||
// no line or num of lines => no diff
|
||||
return ""
|
||||
}
|
||||
scanner := bufio.NewScanner(originalDiff)
|
||||
hunk := make([]string, 0)
|
||||
// begin is the start of the hunk containing searched line
|
||||
// end is the end of the hunk ...
|
||||
// currentLine is the line number on the side of the searched line (differentiated by old)
|
||||
// otherLine is the line number on the opposite side of the searched line (differentiated by old)
|
||||
var begin, end, currentLine, otherLine int64
|
||||
var headerLines int
|
||||
for scanner.Scan() {
|
||||
lof := scanner.Text()
|
||||
// Add header to enable parsing
|
||||
if isHeader(lof) {
|
||||
hunk = append(hunk, lof)
|
||||
headerLines++
|
||||
}
|
||||
if currentLine > line {
|
||||
break
|
||||
}
|
||||
// Detect "hunk" with contains commented lof
|
||||
if strings.HasPrefix(lof, "@@") {
|
||||
// Already got our hunk. End of hunk detected!
|
||||
if len(hunk) > headerLines {
|
||||
break
|
||||
}
|
||||
groups := hunkRegex.FindStringSubmatch(lof)
|
||||
if old {
|
||||
begin = com.StrTo(groups[1]).MustInt64()
|
||||
end = com.StrTo(groups[2]).MustInt64()
|
||||
// init otherLine with begin of opposite side
|
||||
otherLine = com.StrTo(groups[3]).MustInt64()
|
||||
} else {
|
||||
begin = com.StrTo(groups[3]).MustInt64()
|
||||
end = com.StrTo(groups[4]).MustInt64()
|
||||
// init otherLine with begin of opposite side
|
||||
otherLine = com.StrTo(groups[1]).MustInt64()
|
||||
}
|
||||
end += begin // end is for real only the number of lines in hunk
|
||||
// lof is between begin and end
|
||||
if begin <= line && end >= line {
|
||||
hunk = append(hunk, lof)
|
||||
currentLine = begin
|
||||
continue
|
||||
}
|
||||
} else if len(hunk) > headerLines {
|
||||
hunk = append(hunk, lof)
|
||||
// Count lines in context
|
||||
switch lof[0] {
|
||||
case '+':
|
||||
if !old {
|
||||
currentLine++
|
||||
} else {
|
||||
otherLine++
|
||||
}
|
||||
case '-':
|
||||
if old {
|
||||
currentLine++
|
||||
} else {
|
||||
otherLine++
|
||||
}
|
||||
default:
|
||||
currentLine++
|
||||
otherLine++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(hunk)-headerLines < numbersOfLine {
|
||||
// No need to cut the hunk => return existing hunk
|
||||
return strings.Join(hunk, "\n")
|
||||
}
|
||||
var oldBegin, oldNumOfLines, newBegin, newNumOfLines int64
|
||||
if old {
|
||||
oldBegin = currentLine
|
||||
newBegin = otherLine
|
||||
} else {
|
||||
oldBegin = otherLine
|
||||
newBegin = currentLine
|
||||
}
|
||||
// headers + hunk header
|
||||
newHunk := make([]string, headerLines)
|
||||
// transfer existing headers
|
||||
for idx, lof := range hunk[:numbersOfLine] {
|
||||
newHunk[idx] = lof
|
||||
}
|
||||
// transfer last n lines
|
||||
for _, lof := range hunk[len(hunk)-numbersOfLine-1:] {
|
||||
newHunk = append(newHunk, lof)
|
||||
}
|
||||
// calculate newBegin, ... by counting lines
|
||||
for i := len(hunk) - 1; i >= len(hunk)-numbersOfLine; i-- {
|
||||
switch hunk[i][0] {
|
||||
case '+':
|
||||
newBegin--
|
||||
newNumOfLines++
|
||||
case '-':
|
||||
oldBegin--
|
||||
oldNumOfLines++
|
||||
default:
|
||||
oldBegin--
|
||||
newBegin--
|
||||
newNumOfLines++
|
||||
oldNumOfLines++
|
||||
}
|
||||
}
|
||||
// construct the new hunk header
|
||||
newHunk[headerLines] = fmt.Sprintf("@@ -%d,%d +%d,%d @@",
|
||||
oldBegin, oldNumOfLines, newBegin, newNumOfLines)
|
||||
return strings.Join(newHunk, "\n")
|
||||
}
|
||||
|
||||
const cmdDiffHead = "diff --git "
|
||||
|
||||
// ParsePatch builds a Diff object from a io.Reader and some
|
||||
|
@ -335,7 +458,6 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
|||
if curFileLinesCount >= maxLines {
|
||||
curFile.IsIncomplete = true
|
||||
}
|
||||
|
||||
switch {
|
||||
case line[0] == ' ':
|
||||
diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
|
||||
|
|
|
@ -2,6 +2,7 @@ package models
|
|||
|
||||
import (
|
||||
"html/template"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||
|
@ -36,6 +37,42 @@ func TestDiffToHTML(t *testing.T) {
|
|||
}, DiffLineDel))
|
||||
}
|
||||
|
||||
const exampleDiff = `diff --git a/README.md b/README.md
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -1,3 +1,6 @@
|
||||
# gitea-github-migrator
|
||||
+
|
||||
+ Build Status
|
||||
- Latest Release
|
||||
Docker Pulls
|
||||
+ cut off
|
||||
+ cut off`
|
||||
|
||||
func TestCutDiffAroundLine(t *testing.T) {
|
||||
result := CutDiffAroundLine(strings.NewReader(exampleDiff), 4, false, 3)
|
||||
resultByLine := strings.Split(result, "\n")
|
||||
assert.Len(t, resultByLine, 7)
|
||||
// Check if headers got transferred
|
||||
assert.Equal(t, "diff --git a/README.md b/README.md", resultByLine[0])
|
||||
assert.Equal(t, "--- a/README.md", resultByLine[1])
|
||||
assert.Equal(t, "+++ b/README.md", resultByLine[2])
|
||||
// Check if hunk header is calculated correctly
|
||||
assert.Equal(t, "@@ -2,2 +3,2 @@", resultByLine[3])
|
||||
// Check if line got transferred
|
||||
assert.Equal(t, "+ Build Status", resultByLine[4])
|
||||
|
||||
// Must be same result as before since old line 3 == new line 5
|
||||
newResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3)
|
||||
assert.Equal(t, result, newResult, "Must be same result as before since old line 3 == new line 5")
|
||||
|
||||
newResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 300)
|
||||
assert.Equal(t, exampleDiff, newResult)
|
||||
|
||||
emptyResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 0)
|
||||
assert.Empty(t, emptyResult)
|
||||
}
|
||||
|
||||
func TestDiff_LoadComments(t *testing.T) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
issue := AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
|
||||
|
|
|
@ -400,6 +400,10 @@ func (c *Comment) AsDiff() (*Diff, error) {
|
|||
if len(diff.Files) == 0 {
|
||||
return nil, fmt.Errorf("no file found for comment ID: %d", c.ID)
|
||||
}
|
||||
secs := diff.Files[0].Sections
|
||||
if len(secs) == 0 {
|
||||
return nil, fmt.Errorf("no sections found for comment ID: %d", c.ID)
|
||||
}
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
|
@ -755,6 +759,7 @@ func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, tree
|
|||
if err := GetRawDiffForFile(gitRepo.Path, pr.MergeBase, headCommitID, RawDiffNormal, treePath, patchBuf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patch := CutDiffAroundLine(strings.NewReader(patchBuf.String()), int64((&Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
|
||||
|
||||
return CreateComment(&CreateCommentOptions{
|
||||
Type: CommentTypeCode,
|
||||
|
@ -766,7 +771,7 @@ func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, tree
|
|||
TreePath: treePath,
|
||||
CommitSHA: commit.ID.String(),
|
||||
ReviewID: reviewID,
|
||||
Patch: patchBuf.String(),
|
||||
Patch: patch,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user