Browse Source

add diff callback

pull/376/head
Lunny Xiao 11 years ago
parent
commit
ef59a675e7
  1. 5
      cmd/web.go
  2. 159
      models/git_diff.go
  3. 29
      routers/repo/commit.go
  4. 2
      templates/VERSION
  5. 7
      templates/repo/diff.tmpl

5
cmd/web.go

@ -108,6 +108,11 @@ func runWeb(*cli.Context) {
// Repositories. // Repositories.
r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis) r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis)
m.Group("/:username/:reponame", func(r martini.Router) {
r.Get("/commit/:branchname", repo.DiffAjax)
r.Get("/commit/:branchname/**", repo.DiffAjax)
})
r.Any("**", func(ctx *middleware.Context) { r.Any("**", func(ctx *middleware.Context) {
ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL}) ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL})
}) })

159
models/git_diff.go

@ -11,7 +11,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
"time"
"github.com/gogits/git" "github.com/gogits/git"
@ -171,6 +170,10 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
} }
} }
// In case process became zombie.
if err := process.Kill(pid); err != nil {
log.Error("git_diff.ParsePatch(Kill): %v", err)
}
return diff, nil return diff, nil
} }
@ -198,30 +201,152 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
cmd.Stdout = wr cmd.Stdout = wr
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
done := make(chan error)
go func() { go func() {
cmd.Start() cmd.Run()
done <- cmd.Wait()
wr.Close() wr.Close()
}() }()
defer rd.Close() defer rd.Close()
return ParsePatch(process.Add(fmt.Sprintf("GetDiff(%s)", repoPath), cmd), cmd, rd)
}
func ParsePatchCallback(pid int64, cmd *exec.Cmd, reader io.Reader, callback DiffCallback) error {
scanner := bufio.NewScanner(reader)
var (
curFile *DiffFile
curSection = &DiffSection{
Lines: make([]*DiffLine, 0, 10),
}
leftLine, rightLine int
)
var idx = 0
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
continue
}
if line == "" {
continue
}
switch {
case line[0] == ' ':
diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
leftLine++
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
continue
case line[0] == '@':
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
ss := strings.Split(line, "@@")
diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line}
curSection.Lines = append(curSection.Lines, diffLine)
// Parse line number.
ranges := strings.Split(ss[len(ss)-2][1:], " ")
leftLine, _ = base.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
rightLine, _ = base.StrTo(strings.Split(ranges[1], ",")[0]).Int()
continue
case line[0] == '+':
curFile.Addition++
//diff.TotalAddition++
diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine}
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
continue
case line[0] == '-':
curFile.Deletion++
//diff.TotalDeletion++
diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine}
if leftLine > 0 {
leftLine++
}
curSection.Lines = append(curSection.Lines, diffLine)
case strings.HasPrefix(line, "Binary"):
curFile.IsBin = true
continue
}
// Get new file.
if strings.HasPrefix(line, DIFF_HEAD) {
fs := strings.Split(line[len(DIFF_HEAD):], " ")
a := fs[0]
if curFile != nil {
callback(curFile)
}
curFile = &DiffFile{
Name: a[strings.Index(a, "/")+1:],
Index: idx,
Type: DIFF_FILE_CHANGE,
Sections: make([]*DiffSection, 0, 10),
}
idx = idx + 1
// Check file diff type.
for scanner.Scan() {
switch {
case strings.HasPrefix(scanner.Text(), "new file"):
curFile.Type = DIFF_FILE_ADD
case strings.HasPrefix(scanner.Text(), "deleted"):
curFile.Type = DIFF_FILE_DEL
case strings.HasPrefix(scanner.Text(), "index"):
curFile.Type = DIFF_FILE_CHANGE
}
if curFile.Type > 0 {
break
}
}
}
}
if curFile != nil {
callback(curFile)
}
desc := fmt.Sprintf("GetDiff(%s)", repoPath)
pid := process.Add(desc, cmd)
go func() {
// In case process became zombie. // In case process became zombie.
select { if err := process.Kill(pid); err != nil {
case <-time.After(5 * time.Minute):
if errKill := process.Kill(pid); errKill != nil {
log.Error("git_diff.ParsePatch(Kill): %v", err) log.Error("git_diff.ParsePatch(Kill): %v", err)
} }
<-done return nil
// return "", ErrExecTimeout.Error(), ErrExecTimeout
case err = <-done:
process.Remove(pid)
} }
}()
return ParsePatch(pid, cmd, rd) type DiffCallback func(*DiffFile) error
func GetDiffCallback(repoPath, commitid string, callback DiffCallback) error {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return err
}
commit, err := repo.GetCommit(commitid)
if err != nil {
return err
}
rd, wr := io.Pipe()
var cmd *exec.Cmd
// First commit of repository.
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "show", commitid)
} else {
c, _ := commit.Parent(0)
cmd = exec.Command("git", "diff", c.Id.String(), commitid)
}
cmd.Dir = repoPath
cmd.Stdout = wr
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
go func() {
cmd.Run()
wr.Close()
}()
defer rd.Close()
return ParsePatchCallback(process.Add(fmt.Sprintf("GetDiff(%s)", repoPath), cmd),
cmd, rd, callback)
} }

29
routers/repo/commit.go

@ -5,6 +5,7 @@
package repo package repo
import ( import (
"encoding/json"
"path" "path"
"github.com/go-martini/martini" "github.com/go-martini/martini"
@ -105,6 +106,26 @@ func SearchCommits(ctx *middleware.Context, params martini.Params) {
ctx.HTML(200, COMMITS) ctx.HTML(200, COMMITS)
} }
func DiffAjax(ctx *middleware.Context, params martini.Params) {
userName := params["username"]
repoName := params["reponame"]
commitId := params["branchname"]
err := models.GetDiffCallback(models.RepoPath(userName, repoName), commitId, func(f *models.DiffFile) error {
bs, err := json.Marshal(f)
if err != nil {
return err
}
_, err = ctx.Res.Write(bs)
return err
})
if err != nil {
ctx.Handle(404, "repo.DiffAjax", err)
return
}
}
func Diff(ctx *middleware.Context, params martini.Params) { func Diff(ctx *middleware.Context, params martini.Params) {
ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsRepoToolbarCommits"] = true
@ -114,11 +135,11 @@ func Diff(ctx *middleware.Context, params martini.Params) {
commit := ctx.Repo.Commit commit := ctx.Repo.Commit
diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId) /*diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
if err != nil { if err != nil {
ctx.Handle(404, "repo.Diff(GetDiff)", err) ctx.Handle(404, "repo.Diff(GetDiff)", err)
return return
} }*/
isImageFile := func(name string) bool { isImageFile := func(name string) bool {
blob, err := ctx.Repo.Commit.GetBlobByPath(name) blob, err := ctx.Repo.Commit.GetBlobByPath(name)
@ -155,9 +176,9 @@ func Diff(ctx *middleware.Context, params martini.Params) {
ctx.Data["IsImageFile"] = isImageFile ctx.Data["IsImageFile"] = isImageFile
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId) ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
ctx.Data["Commit"] = commit ctx.Data["Commit"] = commit
ctx.Data["Diff"] = diff //ctx.Data["Diff"] = diff
ctx.Data["Parents"] = parents ctx.Data["Parents"] = parents
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 //ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId) ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId) ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
ctx.HTML(200, DIFF) ctx.HTML(200, DIFF)

2
templates/VERSION

@ -1 +1 @@
0.4.5.0707 Alpha 0.4.5.0712 Alpha

7
templates/repo/diff.tmpl

@ -108,4 +108,11 @@
{{end}} {{end}}
</div> </div>
</div> </div>
<script>
$.ajax("https://localhost:3000/api/v1/lunny1/cmd/commit/d049c3fe2dd1f6ed8faad2d7151b3145a632098b", {
success:function(){
alert("dddd")
}
})
</script>
{{template "base/footer" .}} {{template "base/footer" .}}

Loading…
Cancel
Save