aboutsummaryrefslogtreecommitdiffstats
path: root/routers/repo
diff options
context:
space:
mode:
authorKN4CK3R <KN4CK3R@users.noreply.github.com>2021-03-29 22:44:28 +0200
committerGitHub <noreply@github.com>2021-03-29 22:44:28 +0200
commit0c6137617fbf41ee6cb315f96a2acc2dd91203e8 (patch)
tree27c8d1304334f1783232166927093419079ecd2a /routers/repo
parentd3b8127ad372bbce8d891d8893ffe6e834590751 (diff)
downloadgitea-0c6137617fbf41ee6cb315f96a2acc2dd91203e8.tar.gz
gitea-0c6137617fbf41ee6cb315f96a2acc2dd91203e8.zip
Add Tabular Diff for CSV files (#14661)
Implements request #14320 The rendering of CSV files does match the diff style. * Moved CSV logic into base package. * Added method to create a tabular diff. * Added CSV compare context. * Added CSV diff template. * Use new table style in CSV markup. * Added file size limit for CSV rendering. * Display CSV parser errors in diff. * Lazy read single file. * Lazy read rows for full diff. * Added unit tests for various CSV changes.
Diffstat (limited to 'routers/repo')
-rw-r--r--routers/repo/commit.go3
-rw-r--r--routers/repo/compare.go86
-rw-r--r--routers/repo/pull.go6
3 files changed, 87 insertions, 8 deletions
diff --git a/routers/repo/commit.go b/routers/repo/commit.go
index c3ee6b5acc..c06d092613 100644
--- a/routers/repo/commit.go
+++ b/routers/repo/commit.go
@@ -336,9 +336,8 @@ func Diff(ctx *context.Context) {
return
}
}
- setImageCompareContext(ctx, parentCommit, commit)
headTarget := path.Join(userName, repoName)
- setPathsCompareContext(ctx, parentCommit, commit, headTarget)
+ setCompareContext(ctx, parentCommit, commit, headTarget)
ctx.Data["Title"] = commit.Summary() + " ยท " + base.ShortSha(commitID)
ctx.Data["Commit"] = commit
verification := models.ParseCommitWithSignature(commit)
diff --git a/routers/repo/compare.go b/routers/repo/compare.go
index 38c3005cf7..0b7bdf7649 100644
--- a/routers/repo/compare.go
+++ b/routers/repo/compare.go
@@ -6,14 +6,20 @@ package repo
import (
"bufio"
+ "encoding/csv"
+ "errors"
"fmt"
"html"
+ "io/ioutil"
"path"
+ "path/filepath"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/context"
+ csv_module "code.gitea.io/gitea/modules/csv"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -26,6 +32,16 @@ const (
tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
)
+// setCompareContext sets context data.
+func setCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) {
+ ctx.Data["BaseCommit"] = base
+ ctx.Data["HeadCommit"] = head
+
+ setPathsCompareContext(ctx, base, head, headTarget)
+ setImageCompareContext(ctx, base, head)
+ setCsvCompareContext(ctx)
+}
+
// setPathsCompareContext sets context data for source and raw paths
func setPathsCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) {
sourcePath := setting.AppSubURL + "/%s/src/commit/%s"
@@ -65,6 +81,73 @@ func setImageCompareContext(ctx *context.Context, base *git.Commit, head *git.Co
}
}
+// setCsvCompareContext sets context data that is required by the CSV compare template
+func setCsvCompareContext(ctx *context.Context) {
+ ctx.Data["IsCsvFile"] = func(diffFile *gitdiff.DiffFile) bool {
+ extension := strings.ToLower(filepath.Ext(diffFile.Name))
+ return extension == ".csv" || extension == ".tsv"
+ }
+
+ type CsvDiffResult struct {
+ Sections []*gitdiff.TableDiffSection
+ Error string
+ }
+
+ ctx.Data["CreateCsvDiff"] = func(diffFile *gitdiff.DiffFile, baseCommit *git.Commit, headCommit *git.Commit) CsvDiffResult {
+ if diffFile == nil || baseCommit == nil || headCommit == nil {
+ return CsvDiffResult{nil, ""}
+ }
+
+ errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
+
+ csvReaderFromCommit := func(c *git.Commit) (*csv.Reader, error) {
+ blob, err := c.GetBlobByPath(diffFile.Name)
+ if err != nil {
+ return nil, err
+ }
+
+ if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < blob.Size() {
+ return nil, errTooLarge
+ }
+
+ reader, err := blob.DataAsync()
+ if err != nil {
+ return nil, err
+ }
+ defer reader.Close()
+
+ b, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return nil, err
+ }
+
+ b = charset.ToUTF8WithFallback(b)
+
+ return csv_module.CreateReaderAndGuessDelimiter(b), nil
+ }
+
+ baseReader, err := csvReaderFromCommit(baseCommit)
+ if err == errTooLarge {
+ return CsvDiffResult{nil, err.Error()}
+ }
+ headReader, err := csvReaderFromCommit(headCommit)
+ if err == errTooLarge {
+ return CsvDiffResult{nil, err.Error()}
+ }
+
+ sections, err := gitdiff.CreateCsvDiff(diffFile, baseReader, headReader)
+ if err != nil {
+ errMessage, err := csv_module.FormatError(err, ctx.Locale)
+ if err != nil {
+ log.Error("RenderCsvDiff failed: %v", err)
+ return CsvDiffResult{nil, ""}
+ }
+ return CsvDiffResult{nil, errMessage}
+ }
+ return CsvDiffResult{sections, ""}
+ }
+}
+
// ParseCompareInfo parse compare info between two commit for preparing comparing references
func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) {
baseRepo := ctx.Repo.Repository
@@ -490,9 +573,8 @@ func PrepareCompareDiff(
ctx.Data["Username"] = headUser.Name
ctx.Data["Reponame"] = headRepo.Name
- setImageCompareContext(ctx, baseCommit, headCommit)
headTarget := path.Join(headUser.Name, repo.Name)
- setPathsCompareContext(ctx, baseCommit, headCommit, headTarget)
+ setCompareContext(ctx, baseCommit, headCommit, headTarget)
return false
}
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 2ed47605f8..cc6841da47 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -591,7 +591,6 @@ func ViewPullFiles(ctx *context.Context) {
gitRepo *git.Repository
)
- var headTarget string
var prInfo *git.CompareInfo
if pull.HasMerged {
prInfo = PrepareMergedViewPullInfo(ctx, issue)
@@ -618,7 +617,6 @@ func ViewPullFiles(ctx *context.Context) {
startCommitID = prInfo.MergeBase
endCommitID = headCommitID
- headTarget = path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
ctx.Data["AfterCommitID"] = endCommitID
@@ -672,8 +670,8 @@ func ViewPullFiles(ctx *context.Context) {
}
}
- setImageCompareContext(ctx, baseCommit, commit)
- setPathsCompareContext(ctx, baseCommit, commit, headTarget)
+ headTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
+ setCompareContext(ctx, baseCommit, commit, headTarget)
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireSimpleMDE"] = true