summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2019-09-06 10:20:09 +0800
committertechknowlogick <techknowlogick@gitea.io>2019-09-05 22:20:09 -0400
commitc03d75fbd51174d0e7ffdbaf9e9e253438d06cf7 (patch)
treea54e9fdfb6ff96baf7010d7fd5049a05a16644e2 /models
parentb660a732ae283d863636ead9cc1a365ce1c0edc1 (diff)
downloadgitea-c03d75fbd51174d0e7ffdbaf9e9e253438d06cf7.tar.gz
gitea-c03d75fbd51174d0e7ffdbaf9e9e253438d06cf7.zip
Move git diff codes from models to services/gitdiff (#7889)
* move git diff codes from models to services/gitdiff * fix template * fix test * fix template
Diffstat (limited to 'models')
-rw-r--r--models/git_diff.go800
-rw-r--r--models/git_diff_test.go190
-rw-r--r--models/issue_comment.go81
-rw-r--r--models/models.go5
4 files changed, 5 insertions, 1071 deletions
diff --git a/models/git_diff.go b/models/git_diff.go
deleted file mode 100644
index b822685409..0000000000
--- a/models/git_diff.go
+++ /dev/null
@@ -1,800 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package models
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "html"
- "html/template"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "regexp"
- "sort"
- "strconv"
- "strings"
-
- "code.gitea.io/gitea/modules/charset"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/highlight"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/process"
- "code.gitea.io/gitea/modules/setting"
-
- "github.com/sergi/go-diff/diffmatchpatch"
- "github.com/unknwon/com"
- stdcharset "golang.org/x/net/html/charset"
- "golang.org/x/text/transform"
-)
-
-// DiffLineType represents the type of a DiffLine.
-type DiffLineType uint8
-
-// DiffLineType possible values.
-const (
- DiffLinePlain DiffLineType = iota + 1
- DiffLineAdd
- DiffLineDel
- DiffLineSection
-)
-
-// DiffFileType represents the type of a DiffFile.
-type DiffFileType uint8
-
-// DiffFileType possible values.
-const (
- DiffFileAdd DiffFileType = iota + 1
- DiffFileChange
- DiffFileDel
- DiffFileRename
-)
-
-// DiffLine represents a line difference in a DiffSection.
-type DiffLine struct {
- LeftIdx int
- RightIdx int
- Type DiffLineType
- Content string
- Comments []*Comment
-}
-
-// GetType returns the type of a DiffLine.
-func (d *DiffLine) GetType() int {
- return int(d.Type)
-}
-
-// CanComment returns whether or not a line can get commented
-func (d *DiffLine) CanComment() bool {
- return len(d.Comments) == 0 && d.Type != DiffLineSection
-}
-
-// GetCommentSide returns the comment side of the first comment, if not set returns empty string
-func (d *DiffLine) GetCommentSide() string {
- if len(d.Comments) == 0 {
- return ""
- }
- return d.Comments[0].DiffSide()
-}
-
-// GetLineTypeMarker returns the line type marker
-func (d *DiffLine) GetLineTypeMarker() string {
- if strings.IndexByte(" +-", d.Content[0]) > -1 {
- return d.Content[0:1]
- }
- return ""
-}
-
-// escape a line's content or return <br> needed for copy/paste purposes
-func getLineContent(content string) string {
- if len(content) > 0 {
- return html.EscapeString(content)
- }
- return "<br>"
-}
-
-// DiffSection represents a section of a DiffFile.
-type DiffSection struct {
- Name string
- Lines []*DiffLine
-}
-
-var (
- addedCodePrefix = []byte(`<span class="added-code">`)
- removedCodePrefix = []byte(`<span class="removed-code">`)
- codeTagSuffix = []byte(`</span>`)
-)
-
-func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
- buf := bytes.NewBuffer(nil)
-
- for i := range diffs {
- switch {
- case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd:
- buf.Write(addedCodePrefix)
- buf.WriteString(getLineContent(diffs[i].Text))
- buf.Write(codeTagSuffix)
- case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel:
- buf.Write(removedCodePrefix)
- buf.WriteString(getLineContent(diffs[i].Text))
- buf.Write(codeTagSuffix)
- case diffs[i].Type == diffmatchpatch.DiffEqual:
- buf.WriteString(getLineContent(diffs[i].Text))
- }
- }
-
- return template.HTML(buf.Bytes())
-}
-
-// GetLine gets a specific line by type (add or del) and file line number
-func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
- var (
- difference = 0
- addCount = 0
- delCount = 0
- matchDiffLine *DiffLine
- )
-
-LOOP:
- for _, diffLine := range diffSection.Lines {
- switch diffLine.Type {
- case DiffLineAdd:
- addCount++
- case DiffLineDel:
- delCount++
- default:
- if matchDiffLine != nil {
- break LOOP
- }
- difference = diffLine.RightIdx - diffLine.LeftIdx
- addCount = 0
- delCount = 0
- }
-
- switch lineType {
- case DiffLineDel:
- if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
- matchDiffLine = diffLine
- }
- case DiffLineAdd:
- if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
- matchDiffLine = diffLine
- }
- }
- }
-
- if addCount == delCount {
- return matchDiffLine
- }
- return nil
-}
-
-var diffMatchPatch = diffmatchpatch.New()
-
-func init() {
- diffMatchPatch.DiffEditCost = 100
-}
-
-// GetComputedInlineDiffFor computes inline diff for the given line.
-func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
- if setting.Git.DisableDiffHighlight {
- return template.HTML(getLineContent(diffLine.Content[1:]))
- }
- var (
- compareDiffLine *DiffLine
- diff1 string
- diff2 string
- )
-
- // try to find equivalent diff line. ignore, otherwise
- switch diffLine.Type {
- case DiffLineAdd:
- compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
- if compareDiffLine == nil {
- return template.HTML(getLineContent(diffLine.Content[1:]))
- }
- diff1 = compareDiffLine.Content
- diff2 = diffLine.Content
- case DiffLineDel:
- compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
- if compareDiffLine == nil {
- return template.HTML(getLineContent(diffLine.Content[1:]))
- }
- diff1 = diffLine.Content
- diff2 = compareDiffLine.Content
- default:
- if strings.IndexByte(" +-", diffLine.Content[0]) > -1 {
- return template.HTML(getLineContent(diffLine.Content[1:]))
- }
- return template.HTML(getLineContent(diffLine.Content))
- }
-
- diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true)
- diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
-
- return diffToHTML(diffRecord, diffLine.Type)
-}
-
-// DiffFile represents a file diff.
-type DiffFile struct {
- Name string
- OldName string
- Index int
- Addition, Deletion int
- Type DiffFileType
- IsCreated bool
- IsDeleted bool
- IsBin bool
- IsLFSFile bool
- IsRenamed bool
- IsSubmodule bool
- Sections []*DiffSection
- IsIncomplete bool
-}
-
-// GetType returns type of diff file.
-func (diffFile *DiffFile) GetType() int {
- return int(diffFile.Type)
-}
-
-// GetHighlightClass returns highlight class for a filename.
-func (diffFile *DiffFile) GetHighlightClass() string {
- return highlight.FileNameToHighlightClass(diffFile.Name)
-}
-
-// Diff represents a difference between two git trees.
-type Diff struct {
- TotalAddition, TotalDeletion int
- Files []*DiffFile
- IsIncomplete bool
-}
-
-// LoadComments loads comments into each line
-func (diff *Diff) LoadComments(issue *Issue, currentUser *User) error {
- allComments, err := FetchCodeComments(issue, currentUser)
- if err != nil {
- return err
- }
- for _, file := range diff.Files {
- if lineCommits, ok := allComments[file.Name]; ok {
- for _, section := range file.Sections {
- for _, line := range section.Lines {
- if comments, ok := lineCommits[int64(line.LeftIdx*-1)]; ok {
- line.Comments = append(line.Comments, comments...)
- }
- if comments, ok := lineCommits[int64(line.RightIdx)]; ok {
- line.Comments = append(line.Comments, comments...)
- }
- sort.SliceStable(line.Comments, func(i, j int) bool {
- return line.Comments[i].CreatedUnix < line.Comments[j].CreatedUnix
- })
- }
- }
- }
- }
- return nil
-}
-
-// NumFiles returns number of files changes in a diff.
-func (diff *Diff) NumFiles() int {
- return len(diff.Files)
-}
-
-// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
-var hunkRegex = regexp.MustCompile(`^@@ -(?P<beginOld>[0-9]+)(,(?P<endOld>[0-9]+))? \+(?P<beginNew>[0-9]+)(,(?P<endNew>[0-9]+))? @@`)
-
-func isHeader(lof string) bool {
- return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++")
-}
-
-// CutDiffAroundLine cuts a diff of a file in way that only the given line + numberOfLine above it will be shown
-// it also recalculates hunks and adds the appropriate headers to the new diff.
-// Warning: Only one-file diffs are allowed.
-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
- }
- // A map with named groups of our regex to recognize them later more easily
- submatches := hunkRegex.FindStringSubmatch(lof)
- groups := make(map[string]string)
- for i, name := range hunkRegex.SubexpNames() {
- if i != 0 && name != "" {
- groups[name] = submatches[i]
- }
- }
- if old {
- begin = com.StrTo(groups["beginOld"]).MustInt64()
- end = com.StrTo(groups["endOld"]).MustInt64()
- // init otherLine with begin of opposite side
- otherLine = com.StrTo(groups["beginNew"]).MustInt64()
- } else {
- begin = com.StrTo(groups["beginNew"]).MustInt64()
- if groups["endNew"] != "" {
- end = com.StrTo(groups["endNew"]).MustInt64()
- } else {
- end = 0
- }
- // init otherLine with begin of opposite side
- otherLine = com.StrTo(groups["beginOld"]).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++
- }
- }
- }
-
- // No hunk found
- if currentLine == 0 {
- return ""
- }
- // headerLines + hunkLine (1) = totalNonCodeLines
- if len(hunk)-headerLines-1 <= 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
- copy(newHunk, hunk[:headerLines])
- // transfer last n lines
- newHunk = append(newHunk, hunk[len(hunk)-numbersOfLine-1:]...)
- // 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
-// parameters.
-// TODO: move this function to gogits/git-module
-func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) {
- var (
- diff = &Diff{Files: make([]*DiffFile, 0)}
-
- curFile = &DiffFile{}
- curSection = &DiffSection{
- Lines: make([]*DiffLine, 0, 10),
- }
-
- leftLine, rightLine int
- lineCount int
- curFileLinesCount int
- curFileLFSPrefix bool
- )
-
- input := bufio.NewReader(reader)
- isEOF := false
- for !isEOF {
- var linebuf bytes.Buffer
- for {
- b, err := input.ReadByte()
- if err != nil {
- if err == io.EOF {
- isEOF = true
- break
- } else {
- return nil, fmt.Errorf("ReadByte: %v", err)
- }
- }
- if b == '\n' {
- break
- }
- if linebuf.Len() < maxLineCharacters {
- linebuf.WriteByte(b)
- } else if linebuf.Len() == maxLineCharacters {
- curFile.IsIncomplete = true
- }
- }
- line := linebuf.String()
-
- if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 {
- continue
- }
-
- trimLine := strings.Trim(line, "+- ")
-
- if trimLine == LFSMetaFileIdentifier {
- curFileLFSPrefix = true
- }
-
- if curFileLFSPrefix && strings.HasPrefix(trimLine, LFSMetaFileOidPrefix) {
- oid := strings.TrimPrefix(trimLine, LFSMetaFileOidPrefix)
-
- if len(oid) == 64 {
- m := &LFSMetaObject{Oid: oid}
- count, err := x.Count(m)
-
- if err == nil && count > 0 {
- curFile.IsBin = true
- curFile.IsLFSFile = true
- curSection.Lines = nil
- }
- }
- }
-
- curFileLinesCount++
- lineCount++
-
- // Diff data too large, we only show the first about maxLines lines
- if curFileLinesCount >= maxLines {
- curFile.IsIncomplete = true
- }
- switch {
- case line[0] == ' ':
- diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
- leftLine++
- rightLine++
- curSection.Lines = append(curSection.Lines, diffLine)
- continue
- case line[0] == '@':
- curSection = &DiffSection{}
- curFile.Sections = append(curFile.Sections, curSection)
- ss := strings.Split(line, "@@")
- diffLine := &DiffLine{Type: DiffLineSection, Content: line}
- curSection.Lines = append(curSection.Lines, diffLine)
-
- // Parse line number.
- ranges := strings.Split(ss[1][1:], " ")
- leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
- if len(ranges) > 1 {
- rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int()
- } else {
- log.Warn("Parse line number failed: %v", line)
- rightLine = leftLine
- }
- continue
- case line[0] == '+':
- curFile.Addition++
- diff.TotalAddition++
- diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine}
- rightLine++
- curSection.Lines = append(curSection.Lines, diffLine)
- continue
- case line[0] == '-':
- curFile.Deletion++
- diff.TotalDeletion++
- diffLine := &DiffLine{Type: DiffLineDel, Content: line, LeftIdx: leftLine}
- if leftLine > 0 {
- leftLine++
- }
- curSection.Lines = append(curSection.Lines, diffLine)
- case strings.HasPrefix(line, "Binary"):
- curFile.IsBin = true
- continue
- }
-
- // Get new file.
- if strings.HasPrefix(line, cmdDiffHead) {
- var middle int
-
- // Note: In case file name is surrounded by double quotes (it happens only in git-shell).
- // e.g. diff --git "a/xxx" "b/xxx"
- hasQuote := line[len(cmdDiffHead)] == '"'
- if hasQuote {
- middle = strings.Index(line, ` "b/`)
- } else {
- middle = strings.Index(line, " b/")
- }
-
- beg := len(cmdDiffHead)
- a := line[beg+2 : middle]
- b := line[middle+3:]
-
- if hasQuote {
- // Keep the entire string in double quotes for now
- a = line[beg:middle]
- b = line[middle+1:]
-
- var err error
- a, err = strconv.Unquote(a)
- if err != nil {
- return nil, fmt.Errorf("Unquote: %v", err)
- }
- b, err = strconv.Unquote(b)
- if err != nil {
- return nil, fmt.Errorf("Unquote: %v", err)
- }
- // Now remove the /a /b
- a = a[2:]
- b = b[2:]
-
- }
-
- curFile = &DiffFile{
- Name: b,
- OldName: a,
- Index: len(diff.Files) + 1,
- Type: DiffFileChange,
- Sections: make([]*DiffSection, 0, 10),
- IsRenamed: a != b,
- }
- diff.Files = append(diff.Files, curFile)
- if len(diff.Files) >= maxFiles {
- diff.IsIncomplete = true
- _, err := io.Copy(ioutil.Discard, reader)
- if err != nil {
- return nil, fmt.Errorf("Copy: %v", err)
- }
- break
- }
- curFileLinesCount = 0
- curFileLFSPrefix = false
-
- // Check file diff type and is submodule.
- for {
- line, err := input.ReadString('\n')
- if err != nil {
- if err == io.EOF {
- isEOF = true
- } else {
- return nil, fmt.Errorf("ReadString: %v", err)
- }
- }
-
- switch {
- case strings.HasPrefix(line, "new file"):
- curFile.Type = DiffFileAdd
- curFile.IsCreated = true
- case strings.HasPrefix(line, "deleted"):
- curFile.Type = DiffFileDel
- curFile.IsDeleted = true
- case strings.HasPrefix(line, "index"):
- curFile.Type = DiffFileChange
- case strings.HasPrefix(line, "similarity index 100%"):
- curFile.Type = DiffFileRename
- }
- if curFile.Type > 0 {
- if strings.HasSuffix(line, " 160000\n") {
- curFile.IsSubmodule = true
- }
- break
- }
- }
- }
- }
-
- // FIXME: detect encoding while parsing.
- var buf bytes.Buffer
- for _, f := range diff.Files {
- buf.Reset()
- for _, sec := range f.Sections {
- for _, l := range sec.Lines {
- buf.WriteString(l.Content)
- buf.WriteString("\n")
- }
- }
- charsetLabel, err := charset.DetectEncoding(buf.Bytes())
- if charsetLabel != "UTF-8" && err == nil {
- encoding, _ := stdcharset.Lookup(charsetLabel)
- if encoding != nil {
- d := encoding.NewDecoder()
- for _, sec := range f.Sections {
- for _, l := range sec.Lines {
- if c, _, err := transform.String(d, l.Content); err == nil {
- l.Content = c
- }
- }
- }
- }
- }
- }
-
- return diff, nil
-}
-
-// GetDiffRange builds a Diff between two commits of a repository.
-// passing the empty string as beforeCommitID returns a diff from the
-// parent commit.
-func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) {
- return GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID, maxLines, maxLineCharacters, maxFiles, "")
-}
-
-// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
-// Passing the empty string as beforeCommitID returns a diff from the parent commit.
-// The whitespaceBehavior is either an empty string or a git flag
-func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string) (*Diff, error) {
- gitRepo, err := git.OpenRepository(repoPath)
- if err != nil {
- return nil, err
- }
-
- commit, err := gitRepo.GetCommit(afterCommitID)
- if err != nil {
- return nil, err
- }
-
- var cmd *exec.Cmd
- if len(beforeCommitID) == 0 && commit.ParentCount() == 0 {
- cmd = exec.Command(git.GitExecutable, "show", afterCommitID)
- } else {
- actualBeforeCommitID := beforeCommitID
- if len(actualBeforeCommitID) == 0 {
- parentCommit, _ := commit.Parent(0)
- actualBeforeCommitID = parentCommit.ID.String()
- }
- diffArgs := []string{"diff", "-M"}
- if len(whitespaceBehavior) != 0 {
- diffArgs = append(diffArgs, whitespaceBehavior)
- }
- diffArgs = append(diffArgs, actualBeforeCommitID)
- diffArgs = append(diffArgs, afterCommitID)
- cmd = exec.Command(git.GitExecutable, diffArgs...)
- }
- cmd.Dir = repoPath
- cmd.Stderr = os.Stderr
-
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- return nil, fmt.Errorf("StdoutPipe: %v", err)
- }
-
- if err = cmd.Start(); err != nil {
- return nil, fmt.Errorf("Start: %v", err)
- }
-
- pid := process.GetManager().Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cmd)
- defer process.GetManager().Remove(pid)
-
- diff, err := ParsePatch(maxLines, maxLineCharacters, maxFiles, stdout)
- if err != nil {
- return nil, fmt.Errorf("ParsePatch: %v", err)
- }
-
- if err = cmd.Wait(); err != nil {
- return nil, fmt.Errorf("Wait: %v", err)
- }
-
- return diff, nil
-}
-
-// RawDiffType type of a raw diff.
-type RawDiffType string
-
-// RawDiffType possible values.
-const (
- RawDiffNormal RawDiffType = "diff"
- RawDiffPatch RawDiffType = "patch"
-)
-
-// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
-// TODO: move this function to gogits/git-module
-func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
- return GetRawDiffForFile(repoPath, "", commitID, diffType, "", writer)
-}
-
-// GetRawDiffForFile dumps diff results of file in given commit ID to io.Writer.
-// TODO: move this function to gogits/git-module
-func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error {
- repo, err := git.OpenRepository(repoPath)
- if err != nil {
- return fmt.Errorf("OpenRepository: %v", err)
- }
-
- commit, err := repo.GetCommit(endCommit)
- if err != nil {
- return fmt.Errorf("GetCommit: %v", err)
- }
- fileArgs := make([]string, 0)
- if len(file) > 0 {
- fileArgs = append(fileArgs, "--", file)
- }
- var cmd *exec.Cmd
- switch diffType {
- case RawDiffNormal:
- if len(startCommit) != 0 {
- cmd = exec.Command(git.GitExecutable, append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...)
- } else if commit.ParentCount() == 0 {
- cmd = exec.Command(git.GitExecutable, append([]string{"show", endCommit}, fileArgs...)...)
- } else {
- c, _ := commit.Parent(0)
- cmd = exec.Command(git.GitExecutable, append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...)
- }
- case RawDiffPatch:
- if len(startCommit) != 0 {
- query := fmt.Sprintf("%s...%s", endCommit, startCommit)
- cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...)
- } else if commit.ParentCount() == 0 {
- cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...)
- } else {
- c, _ := commit.Parent(0)
- query := fmt.Sprintf("%s...%s", endCommit, c.ID.String())
- cmd = exec.Command(git.GitExecutable, append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...)
- }
- default:
- return fmt.Errorf("invalid diffType: %s", diffType)
- }
-
- stderr := new(bytes.Buffer)
-
- cmd.Dir = repoPath
- cmd.Stdout = writer
- cmd.Stderr = stderr
- if err = cmd.Run(); err != nil {
- return fmt.Errorf("Run: %v - %s", err, stderr)
- }
- return nil
-}
-
-// GetDiffCommit builds a Diff representing the given commitID.
-func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) {
- return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacters, maxFiles)
-}
diff --git a/models/git_diff_test.go b/models/git_diff_test.go
deleted file mode 100644
index bf52095acf..0000000000
--- a/models/git_diff_test.go
+++ /dev/null
@@ -1,190 +0,0 @@
-package models
-
-import (
- "html/template"
- "strings"
- "testing"
-
- "code.gitea.io/gitea/modules/setting"
-
- dmp "github.com/sergi/go-diff/diffmatchpatch"
- "github.com/stretchr/testify/assert"
-)
-
-func assertEqual(t *testing.T, s1 string, s2 template.HTML) {
- if s1 != string(s2) {
- t.Errorf("%s should be equal %s", s2, s1)
- }
-}
-
-func TestDiffToHTML(t *testing.T) {
- assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
- {Type: dmp.DiffEqual, Text: "foo "},
- {Type: dmp.DiffInsert, Text: "bar"},
- {Type: dmp.DiffDelete, Text: " baz"},
- {Type: dmp.DiffEqual, Text: " biz"},
- }, DiffLineAdd))
-
- assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
- {Type: dmp.DiffEqual, Text: "foo "},
- {Type: dmp.DiffDelete, Text: "bar"},
- {Type: dmp.DiffInsert, Text: " baz"},
- {Type: dmp.DiffEqual, Text: " biz"},
- }, 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)
-
- // Line is out of scope
- emptyResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 434, false, 0)
- assert.Empty(t, emptyResult)
-}
-
-func BenchmarkCutDiffAroundLine(b *testing.B) {
- for n := 0; n < b.N; n++ {
- CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3)
- }
-}
-
-func ExampleCutDiffAroundLine() {
- const diff = `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`
- result := CutDiffAroundLine(strings.NewReader(diff), 4, false, 3)
- println(result)
-}
-
-func TestParsePatch(t *testing.T) {
- var diff = `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`
- result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
- if err != nil {
- t.Errorf("ParsePatch failed: %s", err)
- }
- println(result)
-
- var diff2 = `diff --git "a/A \\ B" "b/A \\ B"
---- "a/A \\ B"
-+++ "b/A \\ B"
-@@ -1,3 +1,6 @@
- # gitea-github-migrator
-+
-+ Build Status
-- Latest Release
- Docker Pulls
-+ cut off
-+ cut off`
- result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2))
- if err != nil {
- t.Errorf("ParsePatch failed: %s", err)
- }
- println(result)
-
- var diff3 = `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`
- result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3))
- if err != nil {
- t.Errorf("ParsePatch failed: %s", err)
- }
- println(result)
-}
-
-func setupDefaultDiff() *Diff {
- return &Diff{
- Files: []*DiffFile{
- {
- Name: "README.md",
- Sections: []*DiffSection{
- {
- Lines: []*DiffLine{
- {
- LeftIdx: 4,
- RightIdx: 4,
- },
- },
- },
- },
- },
- },
- }
-}
-func TestDiff_LoadComments(t *testing.T) {
- issue := AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
- user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- diff := setupDefaultDiff()
- assert.NoError(t, PrepareTestDatabase())
- assert.NoError(t, diff.LoadComments(issue, user))
- assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 2)
-}
-
-func TestDiffLine_CanComment(t *testing.T) {
- assert.False(t, (&DiffLine{Type: DiffLineSection}).CanComment())
- assert.False(t, (&DiffLine{Type: DiffLineAdd, Comments: []*Comment{{Content: "bla"}}}).CanComment())
- assert.True(t, (&DiffLine{Type: DiffLineAdd}).CanComment())
- assert.True(t, (&DiffLine{Type: DiffLineDel}).CanComment())
- assert.True(t, (&DiffLine{Type: DiffLinePlain}).CanComment())
-}
-
-func TestDiffLine_GetCommentSide(t *testing.T) {
- assert.Equal(t, "previous", (&DiffLine{Comments: []*Comment{{Line: -3}}}).GetCommentSide())
- assert.Equal(t, "proposed", (&DiffLine{Comments: []*Comment{{Line: 3}}}).GetCommentSide())
-}
diff --git a/models/issue_comment.go b/models/issue_comment.go
index ad1a59e9d3..2a9e8596cb 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -7,7 +7,6 @@
package models
import (
- "bytes"
"fmt"
"strings"
@@ -15,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
- "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@@ -488,32 +486,6 @@ func (c *Comment) UnsignedLine() uint64 {
return uint64(c.Line)
}
-// AsDiff returns c.Patch as *Diff
-func (c *Comment) AsDiff() (*Diff, error) {
- diff, err := ParsePatch(setting.Git.MaxGitDiffLines,
- setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch))
- if err != nil {
- return nil, err
- }
- 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
-}
-
-// MustAsDiff executes AsDiff and logs the error instead of returning
-func (c *Comment) MustAsDiff() *Diff {
- diff, err := c.AsDiff()
- if err != nil {
- log.Warn("MustAsDiff: %v", err)
- }
- return diff
-}
-
// CodeCommentURL returns the url to a comment in code
func (c *Comment) CodeCommentURL() string {
err := c.LoadIssue()
@@ -873,59 +845,6 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
return comment, nil
}
-// CreateCodeComment creates a plain code comment at the specified line / path
-func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, treePath string, line, reviewID int64) (*Comment, error) {
- var commitID, patch string
- pr, err := GetPullRequestByIssueID(issue.ID)
- if err != nil {
- return nil, fmt.Errorf("GetPullRequestByIssueID: %v", err)
- }
- if err := pr.GetBaseRepo(); err != nil {
- return nil, fmt.Errorf("GetHeadRepo: %v", err)
- }
- gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
- if err != nil {
- return nil, fmt.Errorf("OpenRepository: %v", err)
- }
-
- // FIXME validate treePath
- // Get latest commit referencing the commented line
- // No need for get commit for base branch changes
- if line > 0 {
- commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line))
- if err == nil {
- commitID = commit.ID.String()
- } else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") {
- return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err)
- }
- }
-
- // Only fetch diff if comment is review comment
- if reviewID != 0 {
- headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
- if err != nil {
- return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
- }
- patchBuf := new(bytes.Buffer)
- if err := GetRawDiffForFile(gitRepo.Path, pr.MergeBase, headCommitID, RawDiffNormal, treePath, patchBuf); err != nil {
- return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", err, gitRepo.Path, pr.MergeBase, headCommitID, treePath)
- }
- patch = CutDiffAroundLine(patchBuf, int64((&Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
- }
- return CreateComment(&CreateCommentOptions{
- Type: CommentTypeCode,
- Doer: doer,
- Repo: repo,
- Issue: issue,
- Content: content,
- LineNum: line,
- TreePath: treePath,
- CommitSHA: commitID,
- ReviewID: reviewID,
- Patch: patch,
- })
-}
-
// CreateRefComment creates a commit reference comment to issue.
func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commitSHA string) error {
if len(commitSHA) == 0 {
diff --git a/models/models.go b/models/models.go
index 04acc77aa9..e802a35a77 100644
--- a/models/models.go
+++ b/models/models.go
@@ -250,3 +250,8 @@ func MaxBatchInsertSize(bean interface{}) int {
t := x.TableInfo(bean)
return 999 / len(t.ColumnsSeq())
}
+
+// Count returns records number according struct's fields as database query conditions
+func Count(bean interface{}) (int64, error) {
+ return x.Count(bean)
+}