repo2.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "fmt"
  7. "path"
  8. "strings"
  9. "time"
  10. "github.com/Unknwon/com"
  11. "github.com/gogits/git"
  12. )
  13. type Commit struct {
  14. Author string
  15. Email string
  16. Date time.Time
  17. SHA string
  18. Message string
  19. }
  20. var (
  21. ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded")
  22. )
  23. type RepoFile struct {
  24. *git.TreeEntry
  25. Path string
  26. Message string
  27. Created time.Time
  28. Size int64
  29. Repo *git.Repository
  30. LastCommit string
  31. }
  32. func findTree(repo *git.Repository, tree *git.Tree, rpath string) *git.Tree {
  33. if rpath == "" {
  34. return tree
  35. }
  36. paths := strings.Split(rpath, "/")
  37. var g = tree
  38. for _, p := range paths {
  39. s := g.EntryByName(p)
  40. if s == nil {
  41. return nil
  42. }
  43. g, err := repo.LookupTree(s.Id)
  44. if err != nil {
  45. return nil
  46. }
  47. if g == nil {
  48. return nil
  49. }
  50. }
  51. return g
  52. }
  53. func (file *RepoFile) LookupBlob() (*git.Blob, error) {
  54. if file.Repo == nil {
  55. return nil, ErrRepoFileNotLoaded
  56. }
  57. return file.Repo.LookupBlob(file.Id)
  58. }
  59. func GetBranches(userName, reposName string) ([]string, error) {
  60. repo, err := git.OpenRepository(RepoPath(userName, reposName))
  61. if err != nil {
  62. return nil, err
  63. }
  64. refs, err := repo.AllReferences()
  65. if err != nil {
  66. return nil, err
  67. }
  68. brs := make([]string, len(refs))
  69. for i, ref := range refs {
  70. brs[i] = ref.Name
  71. }
  72. return brs, nil
  73. }
  74. func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, error) {
  75. repo, err := git.OpenRepository(RepoPath(userName, reposName))
  76. if err != nil {
  77. return nil, err
  78. }
  79. ref, err := repo.LookupReference("refs/heads/" + branchName)
  80. if err != nil {
  81. return nil, err
  82. }
  83. lastCommit, err := repo.LookupCommit(ref.Oid)
  84. if err != nil {
  85. return nil, err
  86. }
  87. var repodirs []*RepoFile
  88. var repofiles []*RepoFile
  89. lastCommit.Tree.Walk(func(dirname string, entry *git.TreeEntry) int {
  90. if dirname == rpath {
  91. size, err := repo.ObjectSize(entry.Id)
  92. if err != nil {
  93. return 0
  94. }
  95. var cm = lastCommit
  96. for {
  97. if cm.ParentCount() == 0 {
  98. break
  99. } else if cm.ParentCount() == 1 {
  100. pt := findTree(repo, cm.Parent(0).Tree, dirname)
  101. if pt == nil {
  102. break
  103. }
  104. pEntry := pt.EntryByName(entry.Name)
  105. if pEntry == nil || !pEntry.Id.Equal(entry.Id) {
  106. break
  107. } else {
  108. cm = cm.Parent(0)
  109. }
  110. } else {
  111. var emptyCnt = 0
  112. var sameIdcnt = 0
  113. for i := 0; i < cm.ParentCount(); i++ {
  114. p := cm.Parent(i)
  115. pt := findTree(repo, p.Tree, dirname)
  116. var pEntry *git.TreeEntry
  117. if pt != nil {
  118. pEntry = pt.EntryByName(entry.Name)
  119. }
  120. if pEntry == nil {
  121. if emptyCnt == cm.ParentCount()-1 {
  122. goto loop
  123. } else {
  124. emptyCnt = emptyCnt + 1
  125. continue
  126. }
  127. } else {
  128. if !pEntry.Id.Equal(entry.Id) {
  129. goto loop
  130. } else {
  131. if sameIdcnt == cm.ParentCount()-1 {
  132. // TODO: now follow the first parent commit?
  133. cm = cm.Parent(0)
  134. break
  135. }
  136. sameIdcnt = sameIdcnt + 1
  137. }
  138. }
  139. }
  140. }
  141. }
  142. loop:
  143. rp := &RepoFile{
  144. entry,
  145. path.Join(dirname, entry.Name),
  146. cm.Message(),
  147. cm.Committer.When,
  148. size,
  149. repo,
  150. cm.Id().String(),
  151. }
  152. if entry.IsFile() {
  153. repofiles = append(repofiles, rp)
  154. } else if entry.IsDir() {
  155. repodirs = append(repodirs, rp)
  156. }
  157. }
  158. return 0
  159. })
  160. return append(repodirs, repofiles...), nil
  161. }
  162. func GetLastestCommit(userName, repoName string) (*Commit, error) {
  163. stdout, _, err := com.ExecCmd("git", "--git-dir="+RepoPath(userName, repoName), "log", "-1")
  164. if err != nil {
  165. return nil, err
  166. }
  167. commit := new(Commit)
  168. for _, line := range strings.Split(stdout, "\n") {
  169. if len(line) == 0 {
  170. continue
  171. }
  172. switch {
  173. case line[0] == 'c':
  174. commit.SHA = line[7:]
  175. case line[0] == 'A':
  176. infos := strings.SplitN(line, " ", 3)
  177. commit.Author = infos[1]
  178. commit.Email = infos[2][1 : len(infos[2])-1]
  179. case line[0] == 'D':
  180. commit.Date, err = time.Parse("Mon Jan 02 15:04:05 2006 -0700", line[8:])
  181. if err != nil {
  182. return nil, err
  183. }
  184. case line[:4] == " ":
  185. commit.Message = line[4:]
  186. }
  187. }
  188. return commit, nil
  189. }