diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-05-14 11:17:23 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-05-14 11:17:23 +0200 |
| commit | acfd774f464736ec3db293e9205f8e7acb839f04 (patch) | |
| tree | d182a2896711ee45aabdf7555327d24ea2ac982f /pkg/git/git.go | |
| parent | b4df103f7861707a10fa2275823307d8f70bc784 (diff) | |
pkg/git: add bisection functionality
Bisect bisects good..bad commit range against the provided predicate (wrapper around git bisect).
The predicate should return an error only if there is no way to proceed
(it will abort the process), if possible it should prefer to return BisectSkip.
Progress of the process is streamed to the provided trace.
Returns the first commit on which the predicate returns BisectBad.
Update #501
Diffstat (limited to 'pkg/git/git.go')
| -rw-r--r-- | pkg/git/git.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/pkg/git/git.go b/pkg/git/git.go index f7e93825f..59715ed07 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -30,6 +30,7 @@ const ( // This involves fetching/resetting/cloning as necessary to recover from all possible problems. // Returns hash of the HEAD commit in the specified branch. func Poll(dir, repo, branch string) (*Commit, error) { + runSandboxed(dir, "git", "bisect", "reset") runSandboxed(dir, "git", "reset", "--hard") origin, err := runSandboxed(dir, "git", "remote", "get-url", "origin") if err != nil || strings.TrimSpace(string(origin)) != repo { @@ -61,6 +62,7 @@ func Poll(dir, repo, branch string) (*Commit, error) { // CheckoutBranch checkouts the specified repository/branch in dir. func CheckoutBranch(dir, repo, branch string) (*Commit, error) { + runSandboxed(dir, "git", "bisect", "reset") if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil { if err := initRepo(dir); err != nil { return nil, err @@ -78,6 +80,7 @@ func CheckoutBranch(dir, repo, branch string) (*Commit, error) { // CheckoutCommit checkouts the specified repository on the specified commit in dir. func CheckoutCommit(dir, repo, commit string) (*Commit, error) { + runSandboxed(dir, "git", "bisect", "reset") if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil { if err := initRepo(dir); err != nil { return nil, err @@ -318,6 +321,65 @@ func Patch(dir string, patch []byte) error { return nil } +type BisectResult int + +const ( + BisectBad BisectResult = iota + BisectGood + BisectSkip +) + +// Bisect bisects good..bad commit range against the provided predicate (wrapper around git bisect). +// The predicate should return an error only if there is no way to proceed +// (it will abort the process), if possible it should prefer to return BisectSkip. +// Progress of the process is streamed to the provided trace. +// Returns the first commit on which the predicate returns BisectBad. +func Bisect(dir, bad, good string, trace io.Writer, pred func() (BisectResult, error)) (*Commit, error) { + runSandboxed(dir, "git", "bisect", "reset") + runSandboxed(dir, "git", "reset", "--hard") + firstBad, err := GetCommit(dir, bad) + if err != nil { + return nil, err + } + output, err := runSandboxed(dir, "git", "bisect", "start", bad, good) + if err != nil { + return nil, err + } + defer runSandboxed(dir, "git", "bisect", "reset") + fmt.Fprintf(trace, "# git bisect start %v %v\n%s", bad, good, output) + current, err := HeadCommit(dir) + if err != nil { + return nil, err + } + var bisectTerms = [...]string{ + BisectBad: "bad", + BisectGood: "good", + BisectSkip: "skip", + } + for { + res, err := pred() + if err != nil { + return nil, err + } + if res == BisectBad { + firstBad = current + } + output, err = runSandboxed(dir, "git", "bisect", bisectTerms[res]) + if err != nil { + return nil, err + } + fmt.Fprintf(trace, "# git bisect %v %v\n%s", bisectTerms[res], current.Hash, output) + next, err := HeadCommit(dir) + if err != nil { + return nil, err + } + if current.Hash == next.Hash { + return firstBad, nil + } + current = next + } +} + // PreviousReleaseTags returns list of preceding release tags that are reachable from the given commit. // Note: linux-specific. func PreviousReleaseTags(dir, commit string) ([]string, error) { |
