aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-11-21 16:51:08 +0000
committerGitHub <noreply@github.com>2021-11-22 00:51:08 +0800
commit8511eec4d447499e37c1c3fbe3b1f9353ce36190 (patch)
tree2320539c50d2813906d0635b9dbe4b2ba19aadd8 /services
parentd710af6669654f27f02b69d7ef1ba563e7d58a90 (diff)
downloadgitea-8511eec4d447499e37c1c3fbe3b1f9353ce36190.tar.gz
gitea-8511eec4d447499e37c1c3fbe3b1f9353ce36190.zip
Allow Loading of Diffs that are too large (#17739)
* Allow Loading of Diffs that are too large This PR allows the loading of diffs that are suppressed because the file is too large. It does not handle diffs of files which have lines which are too long. Fix #17738 Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'services')
-rw-r--r--services/gitdiff/gitdiff.go96
-rw-r--r--services/gitdiff/gitdiff_test.go11
2 files changed, 65 insertions, 42 deletions
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index c6d11ca89e..c303de0a01 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -695,6 +695,7 @@ const cmdDiffHead = "diff --git "
// ParsePatch builds a Diff object from a io.Reader and some parameters.
func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader, skipToFile string) (*Diff, error) {
+ log.Debug("ParsePatch(%d, %d, %d, ..., %s)", maxLines, maxLineCharacters, maxFiles, skipToFile)
var curFile *DiffFile
skipping := skipToFile != ""
@@ -726,7 +727,7 @@ parsingLoop:
return diff, fmt.Errorf("invalid first file line: %s", line)
}
- if len(diff.Files) >= maxFiles {
+ if maxFiles > -1 && len(diff.Files) >= maxFiles {
lastFile := createDiffFile(diff, line)
diff.End = lastFile.Name
diff.IsIncomplete = true
@@ -1038,7 +1039,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
switch lineBytes[0] {
case '@':
- if curFileLinesCount >= maxLines {
+ if maxLines > -1 && curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
@@ -1075,7 +1076,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
rightLine = lineSectionInfo.RightIdx
continue
case '\\':
- if curFileLinesCount >= maxLines {
+ if maxLines > -1 && curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
@@ -1090,7 +1091,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
case '+':
curFileLinesCount++
curFile.Addition++
- if curFileLinesCount >= maxLines {
+ if maxLines > -1 && curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
@@ -1114,7 +1115,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
case '-':
curFileLinesCount++
curFile.Deletion++
- if curFileLinesCount >= maxLines {
+ if maxLines > -1 && curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
@@ -1134,7 +1135,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
curSection.Lines = append(curSection.Lines, diffLine)
case ' ':
curFileLinesCount++
- if curFileLinesCount >= maxLines {
+ if maxLines > -1 && curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
@@ -1278,13 +1279,25 @@ func readFileName(rd *strings.Reader) (string, bool) {
return name[2:], ambiguity
}
-// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
+// DiffOptions represents the options for a DiffRange
+type DiffOptions struct {
+ BeforeCommitID string
+ AfterCommitID string
+ SkipTo string
+ MaxLines int
+ MaxLineCharacters int
+ MaxFiles int
+ WhitespaceBehavior string
+ DirectComparison bool
+}
+
+// GetDiff 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(gitRepo *git.Repository, beforeCommitID, afterCommitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
+func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
repoPath := gitRepo.Path
- commit, err := gitRepo.GetCommit(afterCommitID)
+ commit, err := gitRepo.GetCommit(opts.AfterCommitID)
if err != nil {
return nil, err
}
@@ -1293,45 +1306,54 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
defer cancel()
argsLength := 6
- if len(whitespaceBehavior) > 0 {
+ if len(opts.WhitespaceBehavior) > 0 {
argsLength++
}
- if len(skipTo) > 0 {
+ if len(opts.SkipTo) > 0 {
argsLength++
}
+ if len(files) > 0 {
+ argsLength += len(files) + 1
+ }
diffArgs := make([]string, 0, argsLength)
- if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
+ if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
- if len(whitespaceBehavior) != 0 {
- diffArgs = append(diffArgs, whitespaceBehavior)
+ if len(opts.WhitespaceBehavior) != 0 {
+ diffArgs = append(diffArgs, opts.WhitespaceBehavior)
}
// append empty tree ref
diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")
- diffArgs = append(diffArgs, afterCommitID)
+ diffArgs = append(diffArgs, opts.AfterCommitID)
} else {
- actualBeforeCommitID := beforeCommitID
+ actualBeforeCommitID := opts.BeforeCommitID
if len(actualBeforeCommitID) == 0 {
parentCommit, _ := commit.Parent(0)
actualBeforeCommitID = parentCommit.ID.String()
}
diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
- if len(whitespaceBehavior) != 0 {
- diffArgs = append(diffArgs, whitespaceBehavior)
+ if len(opts.WhitespaceBehavior) != 0 {
+ diffArgs = append(diffArgs, opts.WhitespaceBehavior)
}
diffArgs = append(diffArgs, actualBeforeCommitID)
- diffArgs = append(diffArgs, afterCommitID)
- beforeCommitID = actualBeforeCommitID
+ diffArgs = append(diffArgs, opts.AfterCommitID)
+ opts.BeforeCommitID = actualBeforeCommitID
}
// In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
// so if we are using at least this version of git we don't have to tell ParsePatch to do
// the skipping for us
- parsePatchSkipToFile := skipTo
- if skipTo != "" && git.CheckGitVersionAtLeast("2.31") == nil {
- diffArgs = append(diffArgs, "--skip-to="+skipTo)
+ parsePatchSkipToFile := opts.SkipTo
+ if opts.SkipTo != "" && git.CheckGitVersionAtLeast("2.31") == nil {
+ diffArgs = append(diffArgs, "--skip-to="+opts.SkipTo)
parsePatchSkipToFile = ""
}
+
+ if len(files) > 0 {
+ diffArgs = append(diffArgs, "--")
+ diffArgs = append(diffArgs, files...)
+ }
+
cmd := exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
cmd.Dir = repoPath
@@ -1349,16 +1371,16 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
pid := process.GetManager().Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cancel)
defer process.GetManager().Remove(pid)
- diff, err := ParsePatch(maxLines, maxLineCharacters, maxFiles, stdout, parsePatchSkipToFile)
+ diff, err := ParsePatch(opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, stdout, parsePatchSkipToFile)
if err != nil {
return nil, fmt.Errorf("unable to ParsePatch: %w", err)
}
- diff.Start = skipTo
+ diff.Start = opts.SkipTo
var checker *git.CheckAttributeReader
if git.CheckGitVersionAtLeast("1.7.8") == nil {
- indexFilename, worktree, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(afterCommitID)
+ indexFilename, worktree, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(opts.AfterCommitID)
if err == nil {
defer deleteTemporaryFile()
@@ -1370,12 +1392,12 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
}
ctx, cancel := context.WithCancel(git.DefaultContext)
if err := checker.Init(ctx); err != nil {
- log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
+ log.Error("Unable to open checker for %s. Error: %v", opts.AfterCommitID, err)
} else {
go func() {
err := checker.Run()
if err != nil && err != ctx.Err() {
- log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
+ log.Error("Unable to open checker for %s. Error: %v", opts.AfterCommitID, err)
}
cancel()
}()
@@ -1426,7 +1448,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
diffFile.IsGenerated = analyze.IsGenerated(diffFile.Name)
}
- tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
+ tailSection := diffFile.GetTailSection(gitRepo, opts.BeforeCommitID, opts.AfterCommitID)
if tailSection != nil {
diffFile.Sections = append(diffFile.Sections, tailSection)
}
@@ -1437,19 +1459,19 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
}
separator := "..."
- if directComparison {
+ if opts.DirectComparison {
separator = ".."
}
- shortstatArgs := []string{beforeCommitID + separator + afterCommitID}
- if len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA {
- shortstatArgs = []string{git.EmptyTreeSHA, afterCommitID}
+ shortstatArgs := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
+ if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
+ shortstatArgs = []string{git.EmptyTreeSHA, opts.AfterCommitID}
}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(repoPath, shortstatArgs...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if base and head have become unrelated.
// previously it would return the results of git diff --shortstat base head so let's try that...
- shortstatArgs = []string{beforeCommitID, afterCommitID}
+ shortstatArgs = []string{opts.BeforeCommitID, opts.AfterCommitID}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(repoPath, shortstatArgs...)
}
if err != nil {
@@ -1459,12 +1481,6 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
return diff, nil
}
-// GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID.
-// The whitespaceBehavior is either an empty string or a git flag
-func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
- return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, skipTo, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison)
-}
-
// CommentAsDiff returns c.Patch as *Diff
func CommentAsDiff(c *models.Comment) (*Diff, error) {
diff, err := ParsePatch(setting.Git.MaxGitDiffLines,
diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go
index 76a8b4e7ca..7d63beffeb 100644
--- a/services/gitdiff/gitdiff_test.go
+++ b/services/gitdiff/gitdiff_test.go
@@ -693,8 +693,15 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) {
}
defer gitRepo.Close()
for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} {
- diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", "",
- setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false)
+ diffs, err := GetDiff(gitRepo,
+ &DiffOptions{
+ AfterCommitID: "bd7063cc7c04689c4d082183d32a604ed27a24f9",
+ BeforeCommitID: "559c156f8e0178b71cb44355428f24001b08fc68",
+ MaxLines: setting.Git.MaxGitDiffLines,
+ MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
+ MaxFiles: setting.Git.MaxGitDiffFiles,
+ WhitespaceBehavior: behavior,
+ })
assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior))
for _, f := range diffs.Files {
assert.True(t, len(f.Sections) > 0, fmt.Sprintf("%s should have sections", f.Name))