mirror of
https://github.com/gogs/gogs.git
synced 2025-12-17 22:00:01 +01:00
git: migrate to github.com/gogs/git-module@v1.0.0 (#5958)
* WIP * Finish `internal/db/git_diff.go` * FInish internal/db/mirror.go * Finish internal/db/pull.go * Finish internal/db/release.go * Finish internal/db/repo.go * Finish internal/db/repo_branch.go * Finish internal/db/repo_editor.go * Finish internal/db/update.go * Save my work * Add license header * Compile! * Merge master * Finish internal/cmd/hook.go * Finish internal/conf/static.go * Finish internal/context/repo.go * Finish internal/db/action.go * Finish internal/db/git_diff.go * Fix submodule URL inferring * Finish internal/db/mirror.go * Updat to beta.4 * css: update fonts * Finish internal/db/pull.go * Finish internal/db/release.go * Finish internal/db/repo_branch.go * Finish internal/db/wiki.go * gitutil: enhance infer submodule UR * Finish internal/route/api/v1/repo/commits.go * mirror: only collect branch commits after sync * mirror: fix tag support * Finish internal/db/repo.go * Finish internal/db/repo_editor.go * Finish internal/db/update.go * Finish internal/gitutil/pull_request.go * Make it compile * Finish internal/route/repo/setting.go * Finish internal/route/repo/branch.go * Finish internal/route/api/v1/repo/file.go * Finish internal/route/repo/download.go * Finish internal/route/repo/editor.go * Use helper * Finish internal/route/repo/issue.go * Finish internal/route/repo/pull.go * Finish internal/route/repo/release.go * Finish internal/route/repo/repo.go * Finish internal/route/repo/wiki.go * Finish internal/route/repo/commit.go * Finish internal/route/repo/view.go * Finish internal/gitutil/tag.go * go.sum
This commit is contained in:
196
internal/gitutil/diff.go
Normal file
196
internal/gitutil/diff.go
Normal file
@@ -0,0 +1,196 @@
|
||||
// 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 gitutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"golang.org/x/net/html/charset"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/gogs/git-module"
|
||||
|
||||
"gogs.io/gogs/internal/conf"
|
||||
"gogs.io/gogs/internal/template/highlight"
|
||||
"gogs.io/gogs/internal/tool"
|
||||
)
|
||||
|
||||
// DiffSection is a wrapper to git.DiffSection with helper methods.
|
||||
type DiffSection struct {
|
||||
*git.DiffSection
|
||||
|
||||
initOnce sync.Once
|
||||
dmp *diffmatchpatch.DiffMatchPatch
|
||||
}
|
||||
|
||||
// ComputedInlineDiffFor computes inline diff for the given line.
|
||||
func (s *DiffSection) ComputedInlineDiffFor(line *git.DiffLine) template.HTML {
|
||||
fallback := template.HTML(html.EscapeString(line.Content))
|
||||
if conf.Git.DisableDiffHighlight {
|
||||
return fallback
|
||||
}
|
||||
|
||||
// Find equivalent diff line, ignore when not found.
|
||||
var diff1, diff2 string
|
||||
switch line.Type {
|
||||
case git.DiffLineAdd:
|
||||
compareLine := s.Line(git.DiffLineDelete, line.RightLine)
|
||||
if compareLine == nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
diff1 = compareLine.Content
|
||||
diff2 = line.Content
|
||||
|
||||
case git.DiffLineDelete:
|
||||
compareLine := s.Line(git.DiffLineAdd, line.LeftLine)
|
||||
if compareLine == nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
diff1 = line.Content
|
||||
diff2 = compareLine.Content
|
||||
|
||||
default:
|
||||
return fallback
|
||||
}
|
||||
|
||||
s.initOnce.Do(func() {
|
||||
s.dmp = diffmatchpatch.New()
|
||||
s.dmp.DiffEditCost = 100
|
||||
})
|
||||
|
||||
diffs := s.dmp.DiffMain(diff1[1:], diff2[1:], true)
|
||||
diffs = s.dmp.DiffCleanupEfficiency(diffs)
|
||||
|
||||
return diffsToHTML(diffs, line.Type)
|
||||
}
|
||||
|
||||
func diffsToHTML(diffs []diffmatchpatch.Diff, lineType git.DiffLineType) template.HTML {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Reproduce signs which are cutted for inline diff before.
|
||||
switch lineType {
|
||||
case git.DiffLineAdd:
|
||||
buf.WriteByte('+')
|
||||
case git.DiffLineDelete:
|
||||
buf.WriteByte('-')
|
||||
}
|
||||
buf.WriteByte(' ')
|
||||
|
||||
const (
|
||||
addedCodePrefix = `<span class="added-code">`
|
||||
removedCodePrefix = `<span class="removed-code">`
|
||||
codeTagSuffix = `</span>`
|
||||
)
|
||||
|
||||
for i := range diffs {
|
||||
switch {
|
||||
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == git.DiffLineAdd:
|
||||
buf.WriteString(addedCodePrefix)
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
buf.WriteString(codeTagSuffix)
|
||||
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == git.DiffLineDelete:
|
||||
buf.WriteString(removedCodePrefix)
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
buf.WriteString(codeTagSuffix)
|
||||
case diffs[i].Type == diffmatchpatch.DiffEqual:
|
||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||
}
|
||||
}
|
||||
|
||||
return template.HTML(buf.Bytes())
|
||||
}
|
||||
|
||||
// DiffFile is a wrapper to git.DiffFile with helper methods.
|
||||
type DiffFile struct {
|
||||
*git.DiffFile
|
||||
Sections []*DiffSection
|
||||
}
|
||||
|
||||
// HighlightClass returns the detected highlight class for the file.
|
||||
func (diffFile *DiffFile) HighlightClass() string {
|
||||
return highlight.FileNameToHighlightClass(diffFile.Name)
|
||||
}
|
||||
|
||||
// Diff is a wrapper to git.Diff with helper methods.
|
||||
type Diff struct {
|
||||
*git.Diff
|
||||
Files []*DiffFile
|
||||
}
|
||||
|
||||
// NewDiff returns a new wrapper of given git.Diff.
|
||||
func NewDiff(oldDiff *git.Diff) *Diff {
|
||||
newDiff := &Diff{
|
||||
Diff: oldDiff,
|
||||
Files: make([]*DiffFile, oldDiff.NumFiles()),
|
||||
}
|
||||
|
||||
// FIXME: detect encoding while parsing.
|
||||
var buf bytes.Buffer
|
||||
for i := range oldDiff.Files {
|
||||
buf.Reset()
|
||||
|
||||
newDiff.Files[i] = &DiffFile{
|
||||
DiffFile: oldDiff.Files[i],
|
||||
Sections: make([]*DiffSection, oldDiff.Files[i].NumSections()),
|
||||
}
|
||||
|
||||
for j := range oldDiff.Files[i].Sections {
|
||||
newDiff.Files[i].Sections[j] = &DiffSection{
|
||||
DiffSection: oldDiff.Files[i].Sections[j],
|
||||
}
|
||||
|
||||
for k := range newDiff.Files[i].Sections[j].Lines {
|
||||
buf.WriteString(newDiff.Files[i].Sections[j].Lines[k].Content)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
charsetLabel, err := tool.DetectEncoding(buf.Bytes())
|
||||
if charsetLabel != "UTF-8" && err == nil {
|
||||
encoding, _ := charset.Lookup(charsetLabel)
|
||||
if encoding != nil {
|
||||
d := encoding.NewDecoder()
|
||||
for j := range newDiff.Files[i].Sections {
|
||||
for k := range newDiff.Files[i].Sections[j].Lines {
|
||||
if c, _, err := transform.String(d, newDiff.Files[i].Sections[j].Lines[k].Content); err == nil {
|
||||
newDiff.Files[i].Sections[j].Lines[k].Content = c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newDiff
|
||||
}
|
||||
|
||||
// ParseDiff parses the diff from given io.Reader.
|
||||
func ParseDiff(r io.Reader, maxFiles, maxFileLines, maxLineChars int) (*Diff, error) {
|
||||
done := make(chan git.SteamParseDiffResult)
|
||||
go git.StreamParseDiff(r, done, maxFiles, maxFileLines, maxLineChars)
|
||||
|
||||
result := <-done
|
||||
if result.Err != nil {
|
||||
return nil, fmt.Errorf("stream parse diff: %v", result.Err)
|
||||
}
|
||||
return NewDiff(result.Diff), nil
|
||||
}
|
||||
|
||||
// RepoDiff parses the diff on given revisions of given repository.
|
||||
func RepoDiff(repo *git.Repository, rev string, maxFiles, maxFileLines, maxLineChars int, opts ...git.DiffOptions) (*Diff, error) {
|
||||
diff, err := repo.Diff(rev, maxFiles, maxFileLines, maxLineChars, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get diff: %v", err)
|
||||
}
|
||||
return NewDiff(diff), nil
|
||||
}
|
||||
Reference in New Issue
Block a user