diff --git a/models/git.go b/models/git.go index b0b0dd2f84..5b2a4060b4 100644 --- a/models/git.go +++ b/models/git.go @@ -9,8 +9,10 @@ import ( "fmt" "path" "strings" - - "github.com/Unknwon/com" + "io" + "bufio" + "os" + "os/exec" "github.com/gogits/git" ) @@ -226,20 +228,150 @@ func GetCommits(userName, reposName, branchname string) (*list.List, error) { return r.AllCommits() } +const ( + PlainLine = iota + 1 + AddLine + DelLine + SectionLine +) + +const ( + AddFile = iota + 1 + ChangeFile + DelFile +) + +type DiffLine struct { + LeftIdx int + RightIdx int + Type int + Content string +} + +type DiffSection struct { + Name string + Lines []*DiffLine +} + type DiffFile struct { Name string Addition, Deletion int - Type string - Content []string + Type int + Sections []*DiffSection } type Diff struct { - NumFiles int // Number of file has been changed. TotalAddition, TotalDeletion int Files []*DiffFile } +func (diff *Diff) NumFiles() int { + return len(diff.Files) +} + +const diffHead = "diff --git " + +func ParsePatch(reader io.Reader) (*Diff, error) { + scanner := bufio.NewScanner(reader) + var totalAdd, totalDel int + var curFile *DiffFile + var curSection * DiffSection + //var leftLine, rightLine int + diff := &Diff{Files:make([]*DiffFile, 0)} + var i int + for scanner.Scan() { + line := scanner.Text() + fmt.Println(i, line) + i = i + 1 + if line == "" { + continue + } + if line[0] == ' ' { + diffLine := &DiffLine{Type: PlainLine, Content:line} + curSection.Lines = append(curSection.Lines, diffLine) + continue + } else if line[0] == '@' { + ss := strings.Split(line, "@@") + diffLine := &DiffLine{Type: SectionLine, Content:"@@ "+ss[len(ss)-2]} + curSection.Lines = append(curSection.Lines, diffLine) + + + + diffLine = &DiffLine{Type: PlainLine, Content:ss[len(ss)-1]} + curSection.Lines = append(curSection.Lines, diffLine) + continue + } else if line[0] == '+' { + diffLine := &DiffLine{Type: AddLine, Content:line} + curSection.Lines = append(curSection.Lines, diffLine) + continue + } else if line[0] == '-' { + diffLine := &DiffLine{Type: DelLine, Content:line} + curSection.Lines = append(curSection.Lines, diffLine) + continue + } + + if strings.HasPrefix(line, diffHead) { + if curFile != nil { + curFile.Addition, totalAdd = totalAdd, 0 + curFile.Deletion, totalDel = totalDel, 0 + curFile = nil + } + fs := strings.Split(line[len(diffHead):], " ") + a := fs[0] + + curFile = &DiffFile{ + Name:a[strings.Index(a, "/")+1:], + Type: ChangeFile, + Sections:make([]*DiffSection, 0), + } + diff.Files = append(diff.Files, curFile) + scanner.Scan() + scanner.Scan() + if scanner.Text() == "--- /dev/null" { + curFile.Type = AddFile + } + scanner.Scan() + } + } + + return diff, nil +} + func GetDiff(repoPath, commitid string) (*Diff, error) { + repo, err := git.OpenRepository(repoPath) + if err != nil { + return nil, err + } + + commit, err := repo.GetCommit("", commitid) + if err != nil { + return nil, err + } + + if commit.ParentCount() == 0 { + return nil, err + } + + rd, wr := io.Pipe() + go func() { + cmd := exec.Command("git", "diff", commitid, commit.Parent(0).Oid.String()) + cmd.Dir = repoPath + cmd.Stdout = wr + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + cmd.Run() + //if err != nil { + // return nil, err + //} + wr.Close() + }() + + defer rd.Close() + + return ParsePatch(rd) +} + +/*func GetDiff(repoPath, commitid string) (*Diff, error) { stdout, _, err := com.ExecCmdDir(repoPath, "git", "show", commitid) if err != nil { return nil, err @@ -271,4 +403,4 @@ func GetDiff(repoPath, commitid string) (*Diff, error) { diff.Files = append(diff.Files, file) } return diff, nil -} +}*/