From c39e0b3cbaef4d87c6d63a71c2090d8873491ea7 Mon Sep 17 00:00:00 2001 From: Mura Li Date: Sun, 27 Nov 2016 18:40:44 +0800 Subject: [PATCH 1/3] Speed up conflict checking in pull request creation In order to check conflicts of a PR, we set up a working tree by cloning the base branch, which is quite time-consuming when the repository is huge. Instead, this PR uses `git read-tree` and `git apply --check --cached` to check conflicts. For #258 --- models/pull.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/models/pull.go b/models/pull.go index 9aec3596d430a..805aef8dfb04b 100644 --- a/models/pull.go +++ b/models/pull.go @@ -8,6 +8,8 @@ import ( "fmt" "os" "path" + "path/filepath" + "strconv" "strings" "time" @@ -428,17 +430,22 @@ func (pr *PullRequest) testPatch() (err error) { log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath) - // Delete old temp local copy before we create a new temp local copy - RemoveAllWithNotice("Deleting old local copy", pr.BaseRepo.LocalCopyPath()) + pr.Status = PullRequestStatusChecking + + indexTmpPath := filepath.Join(os.TempDir(), "-gitea-"+pr.BaseRepo.Name+"-"+strconv.Itoa(time.Now().Nanosecond())) + defer os.Remove(indexTmpPath) - if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil { - return fmt.Errorf("UpdateLocalCopy: %v", err) + var stderr string + _, stderr, err = process.ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git read-tree): %d", pr.BaseRepo.ID), + []string{"GIT_DIR=" + pr.BaseRepo.RepoPath()}, + "git", "read-tree", "--index-output", indexTmpPath, pr.BaseBranch) + if err != nil { + return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr) } - pr.Status = PullRequestStatusChecking - _, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(), - fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID), - "git", "apply", "--check", patchPath) + _, stderr, err = process.ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID), + []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}, + "git", "apply", "--check", "--cached", patchPath) if err != nil { for i := range patchConflicts { if strings.Contains(stderr, patchConflicts[i]) { From f349204ea98cf5d8135d75ae361f4d4e8c29d737 Mon Sep 17 00:00:00 2001 From: Mura Li Date: Wed, 28 Dec 2016 03:20:52 +0000 Subject: [PATCH 2/3] Use $GIT_INDEX_FILE instead of --index-output to avoid lockfile problem The lockfile gets renamed to the final destination after the operation finishes. But it must be located in the same filesystem, which prevents us from using /tmp. --- models/pull.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/pull.go b/models/pull.go index 805aef8dfb04b..be6a13a44e097 100644 --- a/models/pull.go +++ b/models/pull.go @@ -437,8 +437,8 @@ func (pr *PullRequest) testPatch() (err error) { var stderr string _, stderr, err = process.ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git read-tree): %d", pr.BaseRepo.ID), - []string{"GIT_DIR=" + pr.BaseRepo.RepoPath()}, - "git", "read-tree", "--index-output", indexTmpPath, pr.BaseBranch) + []string{"GIT_DIR=" + pr.BaseRepo.RepoPath(), "GIT_INDEX_FILE=" + indexTmpPath}, + "git", "read-tree", pr.BaseBranch) if err != nil { return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr) } From f635203d9f02e173c8f8162181af40d1aab5b2e7 Mon Sep 17 00:00:00 2001 From: Mura Li Date: Thu, 29 Dec 2016 19:59:07 +0800 Subject: [PATCH 3/3] Temporary file names should not prefixed with '-' --- models/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/pull.go b/models/pull.go index be6a13a44e097..36194d8660b88 100644 --- a/models/pull.go +++ b/models/pull.go @@ -432,7 +432,7 @@ func (pr *PullRequest) testPatch() (err error) { pr.Status = PullRequestStatusChecking - indexTmpPath := filepath.Join(os.TempDir(), "-gitea-"+pr.BaseRepo.Name+"-"+strconv.Itoa(time.Now().Nanosecond())) + indexTmpPath := filepath.Join(os.TempDir(), "gitea-"+pr.BaseRepo.Name+"-"+strconv.Itoa(time.Now().Nanosecond())) defer os.Remove(indexTmpPath) var stderr string