diff options
author | KN4CK3R <KN4CK3R@users.noreply.github.com> | 2021-03-29 22:44:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-29 22:44:28 +0200 |
commit | 0c6137617fbf41ee6cb315f96a2acc2dd91203e8 (patch) | |
tree | 27c8d1304334f1783232166927093419079ecd2a /routers/repo | |
parent | d3b8127ad372bbce8d891d8893ffe6e834590751 (diff) | |
download | gitea-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.go | 3 | ||||
-rw-r--r-- | routers/repo/compare.go | 86 | ||||
-rw-r--r-- | routers/repo/pull.go | 6 |
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 |