|
@@ -12,15 +12,14 @@ import (
|
|
"os"
|
|
"os"
|
|
"os/exec"
|
|
"os/exec"
|
|
"strings"
|
|
"strings"
|
|
- "time"
|
|
|
|
|
|
|
|
|
|
+ "github.com/Unknwon/com"
|
|
"golang.org/x/net/html/charset"
|
|
"golang.org/x/net/html/charset"
|
|
"golang.org/x/text/transform"
|
|
"golang.org/x/text/transform"
|
|
|
|
|
|
- "github.com/Unknwon/com"
|
|
|
|
|
|
+ "github.com/gogits/git-shell"
|
|
|
|
|
|
"github.com/gogits/gogs/modules/base"
|
|
"github.com/gogits/gogs/modules/base"
|
|
- "github.com/gogits/gogs/modules/git"
|
|
|
|
"github.com/gogits/gogs/modules/log"
|
|
"github.com/gogits/gogs/modules/log"
|
|
"github.com/gogits/gogs/modules/process"
|
|
"github.com/gogits/gogs/modules/process"
|
|
)
|
|
)
|
|
@@ -80,36 +79,50 @@ func (diff *Diff) NumFiles() int {
|
|
|
|
|
|
const DIFF_HEAD = "diff --git "
|
|
const DIFF_HEAD = "diff --git "
|
|
|
|
|
|
-func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
|
|
|
|
- scanner := bufio.NewScanner(reader)
|
|
|
|
|
|
+func ParsePatch(maxlines int, reader io.Reader) (*Diff, error) {
|
|
var (
|
|
var (
|
|
|
|
+ diff = &Diff{Files: make([]*DiffFile, 0)}
|
|
|
|
+
|
|
curFile *DiffFile
|
|
curFile *DiffFile
|
|
curSection = &DiffSection{
|
|
curSection = &DiffSection{
|
|
Lines: make([]*DiffLine, 0, 10),
|
|
Lines: make([]*DiffLine, 0, 10),
|
|
}
|
|
}
|
|
|
|
|
|
leftLine, rightLine int
|
|
leftLine, rightLine int
|
|
- // FIXME: Should use cache in the future.
|
|
|
|
- buf bytes.Buffer
|
|
|
|
|
|
+ lineCount int
|
|
)
|
|
)
|
|
|
|
|
|
- diff := &Diff{Files: make([]*DiffFile, 0)}
|
|
|
|
- var i int
|
|
|
|
- for scanner.Scan() {
|
|
|
|
- line := scanner.Text()
|
|
|
|
|
|
+ input := bufio.NewReader(reader)
|
|
|
|
+ isEOF := false
|
|
|
|
+ for {
|
|
|
|
+ if isEOF {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
|
|
- if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
|
|
|
|
- continue
|
|
|
|
|
|
+ line, err := input.ReadString('\n')
|
|
|
|
+ if err != nil {
|
|
|
|
+ if err == io.EOF {
|
|
|
|
+ isEOF = true
|
|
|
|
+ } else {
|
|
|
|
+ return nil, fmt.Errorf("ReadString: %v", err)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if len(line) > 0 && line[len(line)-1] == '\n' {
|
|
|
|
+ // Remove line break.
|
|
|
|
+ line = line[:len(line)-1]
|
|
}
|
|
}
|
|
|
|
|
|
- if line == "" {
|
|
|
|
|
|
+ if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
|
|
|
|
+ continue
|
|
|
|
+ } else if len(line) == 0 {
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
|
|
|
|
- i = i + 1
|
|
|
|
|
|
+ lineCount++
|
|
|
|
|
|
// Diff data too large, we only show the first about maxlines lines
|
|
// Diff data too large, we only show the first about maxlines lines
|
|
- if i >= maxlines {
|
|
|
|
|
|
+ if lineCount >= maxlines {
|
|
log.Warn("Diff data too large")
|
|
log.Warn("Diff data too large")
|
|
diff.Files = nil
|
|
diff.Files = nil
|
|
return diff, nil
|
|
return diff, nil
|
|
@@ -189,17 +202,26 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
|
diff.Files = append(diff.Files, curFile)
|
|
diff.Files = append(diff.Files, curFile)
|
|
|
|
|
|
// Check file diff type.
|
|
// Check file diff type.
|
|
- for scanner.Scan() {
|
|
|
|
|
|
+ for {
|
|
|
|
+ line, err := input.ReadString('\n')
|
|
|
|
+ if err != nil {
|
|
|
|
+ if err == io.EOF {
|
|
|
|
+ isEOF = true
|
|
|
|
+ } else {
|
|
|
|
+ return nil, fmt.Errorf("ReadString: %v", err)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
switch {
|
|
switch {
|
|
- case strings.HasPrefix(scanner.Text(), "new file"):
|
|
|
|
|
|
+ case strings.HasPrefix(line, "new file"):
|
|
curFile.Type = DIFF_FILE_ADD
|
|
curFile.Type = DIFF_FILE_ADD
|
|
curFile.IsCreated = true
|
|
curFile.IsCreated = true
|
|
- case strings.HasPrefix(scanner.Text(), "deleted"):
|
|
|
|
|
|
+ case strings.HasPrefix(line, "deleted"):
|
|
curFile.Type = DIFF_FILE_DEL
|
|
curFile.Type = DIFF_FILE_DEL
|
|
curFile.IsDeleted = true
|
|
curFile.IsDeleted = true
|
|
- case strings.HasPrefix(scanner.Text(), "index"):
|
|
|
|
|
|
+ case strings.HasPrefix(line, "index"):
|
|
curFile.Type = DIFF_FILE_CHANGE
|
|
curFile.Type = DIFF_FILE_CHANGE
|
|
- case strings.HasPrefix(scanner.Text(), "similarity index 100%"):
|
|
|
|
|
|
+ case strings.HasPrefix(line, "similarity index 100%"):
|
|
curFile.Type = DIFF_FILE_RENAME
|
|
curFile.Type = DIFF_FILE_RENAME
|
|
curFile.IsRenamed = true
|
|
curFile.IsRenamed = true
|
|
curFile.OldName = curFile.Name
|
|
curFile.OldName = curFile.Name
|
|
@@ -212,6 +234,8 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // FIXME: detect encoding while parsing.
|
|
|
|
+ var buf bytes.Buffer
|
|
for _, f := range diff.Files {
|
|
for _, f := range diff.Files {
|
|
buf.Reset()
|
|
buf.Reset()
|
|
for _, sec := range f.Sections {
|
|
for _, sec := range f.Sections {
|
|
@@ -238,61 +262,55 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
|
|
return diff, nil
|
|
return diff, nil
|
|
}
|
|
}
|
|
|
|
|
|
-func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) {
|
|
|
|
|
|
+func GetDiffRange(repoPath, beforeCommitID string, afterCommitID string, maxlines int) (*Diff, error) {
|
|
repo, err := git.OpenRepository(repoPath)
|
|
repo, err := git.OpenRepository(repoPath)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
- commit, err := repo.GetCommit(afterCommitId)
|
|
|
|
|
|
+ commit, err := repo.GetCommit(afterCommitID)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
- rd, wr := io.Pipe()
|
|
|
|
var cmd *exec.Cmd
|
|
var cmd *exec.Cmd
|
|
// if "after" commit given
|
|
// if "after" commit given
|
|
- if beforeCommitId == "" {
|
|
|
|
|
|
+ if len(beforeCommitID) == 0 {
|
|
// First commit of repository.
|
|
// First commit of repository.
|
|
if commit.ParentCount() == 0 {
|
|
if commit.ParentCount() == 0 {
|
|
- cmd = exec.Command("git", "show", afterCommitId)
|
|
|
|
|
|
+ cmd = exec.Command("git", "show", afterCommitID)
|
|
} else {
|
|
} else {
|
|
c, _ := commit.Parent(0)
|
|
c, _ := commit.Parent(0)
|
|
- cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitId)
|
|
|
|
|
|
+ cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitID)
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- cmd = exec.Command("git", "diff", "-M", beforeCommitId, afterCommitId)
|
|
|
|
|
|
+ cmd = exec.Command("git", "diff", "-M", beforeCommitID, afterCommitID)
|
|
}
|
|
}
|
|
cmd.Dir = repoPath
|
|
cmd.Dir = repoPath
|
|
- cmd.Stdout = wr
|
|
|
|
- cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Stderr = os.Stderr
|
|
|
|
|
|
- done := make(chan error)
|
|
|
|
- go func() {
|
|
|
|
- cmd.Start()
|
|
|
|
- done <- cmd.Wait()
|
|
|
|
- wr.Close()
|
|
|
|
- }()
|
|
|
|
- defer rd.Close()
|
|
|
|
-
|
|
|
|
- desc := fmt.Sprintf("GetDiffRange(%s)", repoPath)
|
|
|
|
- pid := process.Add(desc, cmd)
|
|
|
|
- go func() {
|
|
|
|
- // In case process became zombie.
|
|
|
|
- select {
|
|
|
|
- case <-time.After(5 * time.Minute):
|
|
|
|
- if errKill := process.Kill(pid); errKill != nil {
|
|
|
|
- log.Error(4, "git_diff.ParsePatch(Kill): %v", err)
|
|
|
|
- }
|
|
|
|
- <-done
|
|
|
|
- // return "", ErrExecTimeout.Error(), ErrExecTimeout
|
|
|
|
- case err = <-done:
|
|
|
|
- process.Remove(pid)
|
|
|
|
- }
|
|
|
|
- }()
|
|
|
|
|
|
+ stdout, err := cmd.StdoutPipe()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("StdoutPipe: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err = cmd.Start(); err != nil {
|
|
|
|
+ return nil, fmt.Errorf("Start: %v", err)
|
|
|
|
+ }
|
|
|
|
|
|
- return ParsePatch(pid, maxlines, cmd, rd)
|
|
|
|
|
|
+ pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
|
|
|
|
+ defer process.Remove(pid)
|
|
|
|
+
|
|
|
|
+ diff, err := ParsePatch(maxlines, stdout)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("ParsePatch: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err = cmd.Wait(); err != nil {
|
|
|
|
+ return nil, fmt.Errorf("Wait: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return diff, nil
|
|
}
|
|
}
|
|
|
|
|
|
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {
|
|
func GetDiffCommit(repoPath, commitId string, maxlines int) (*Diff, error) {
|