You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

commit.go 9.6 kB

11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 repo
  5. import (
  6. "container/list"
  7. "path"
  8. "strings"
  9. "code.gitea.io/git"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/base"
  12. "code.gitea.io/gitea/modules/context"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. "github.com/Unknwon/paginater"
  16. )
  17. const (
  18. tplCommits base.TplName = "repo/commits"
  19. tplGraph base.TplName = "repo/graph"
  20. tplDiff base.TplName = "repo/diff/page"
  21. )
  22. // RefCommits render commits page
  23. func RefCommits(ctx *context.Context) {
  24. switch {
  25. case len(ctx.Repo.TreePath) == 0:
  26. Commits(ctx)
  27. case ctx.Repo.TreePath == "search":
  28. SearchCommits(ctx)
  29. default:
  30. FileHistory(ctx)
  31. }
  32. }
  33. func renderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
  34. newCommits := list.New()
  35. for e := oldCommits.Front(); e != nil; e = e.Next() {
  36. c := e.Value.(*git.Commit)
  37. newCommits.PushBack(c)
  38. }
  39. return newCommits
  40. }
  41. // Commits render branch's commits
  42. func Commits(ctx *context.Context) {
  43. ctx.Data["PageIsCommits"] = true
  44. if ctx.Repo.Commit == nil {
  45. ctx.Handle(404, "Commit not found", nil)
  46. return
  47. }
  48. commitsCount, err := ctx.Repo.Commit.CommitsCount()
  49. if err != nil {
  50. ctx.Handle(500, "GetCommitsCount", err)
  51. return
  52. }
  53. page := ctx.QueryInt("page")
  54. if page <= 1 {
  55. page = 1
  56. }
  57. ctx.Data["Page"] = paginater.New(int(commitsCount), git.CommitsRangeSize, page, 5)
  58. // Both `git log branchName` and `git log commitId` work.
  59. commits, err := ctx.Repo.Commit.CommitsByRange(page)
  60. if err != nil {
  61. ctx.Handle(500, "CommitsByRange", err)
  62. return
  63. }
  64. commits = renderIssueLinks(commits, ctx.Repo.RepoLink)
  65. commits = models.ValidateCommitsWithEmails(commits)
  66. commits = models.ParseCommitsWithSignature(commits)
  67. commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
  68. ctx.Data["Commits"] = commits
  69. ctx.Data["Username"] = ctx.Repo.Owner.Name
  70. ctx.Data["Reponame"] = ctx.Repo.Repository.Name
  71. ctx.Data["CommitCount"] = commitsCount
  72. ctx.Data["Branch"] = ctx.Repo.BranchName
  73. ctx.HTML(200, tplCommits)
  74. }
  75. // Graph render commit graph - show commits from all branches.
  76. func Graph(ctx *context.Context) {
  77. ctx.Data["PageIsCommits"] = true
  78. commitsCount, err := ctx.Repo.Commit.CommitsCount()
  79. if err != nil {
  80. ctx.Handle(500, "GetCommitsCount", err)
  81. return
  82. }
  83. graph, err := models.GetCommitGraph(ctx.Repo.GitRepo)
  84. if err != nil {
  85. ctx.Handle(500, "GetCommitGraph", err)
  86. return
  87. }
  88. ctx.Data["Graph"] = graph
  89. ctx.Data["Username"] = ctx.Repo.Owner.Name
  90. ctx.Data["Reponame"] = ctx.Repo.Repository.Name
  91. ctx.Data["CommitCount"] = commitsCount
  92. ctx.Data["Branch"] = ctx.Repo.BranchName
  93. ctx.Data["RequireGitGraph"] = true
  94. ctx.HTML(200, tplGraph)
  95. }
  96. // SearchCommits render commits filtered by keyword
  97. func SearchCommits(ctx *context.Context) {
  98. ctx.Data["PageIsCommits"] = true
  99. keyword := strings.Trim(ctx.Query("q"), " ")
  100. if len(keyword) == 0 {
  101. ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
  102. return
  103. }
  104. all := ctx.QueryBool("all")
  105. commits, err := ctx.Repo.Commit.SearchCommits(keyword, all)
  106. if err != nil {
  107. ctx.Handle(500, "SearchCommits", err)
  108. return
  109. }
  110. commits = renderIssueLinks(commits, ctx.Repo.RepoLink)
  111. commits = models.ValidateCommitsWithEmails(commits)
  112. commits = models.ParseCommitsWithSignature(commits)
  113. commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
  114. ctx.Data["Commits"] = commits
  115. ctx.Data["Keyword"] = keyword
  116. if all {
  117. ctx.Data["All"] = "checked"
  118. }
  119. ctx.Data["Username"] = ctx.Repo.Owner.Name
  120. ctx.Data["Reponame"] = ctx.Repo.Repository.Name
  121. ctx.Data["CommitCount"] = commits.Len()
  122. ctx.Data["Branch"] = ctx.Repo.BranchName
  123. ctx.HTML(200, tplCommits)
  124. }
  125. // FileHistory show a file's reversions
  126. func FileHistory(ctx *context.Context) {
  127. ctx.Data["IsRepoToolbarCommits"] = true
  128. fileName := ctx.Repo.TreePath
  129. if len(fileName) == 0 {
  130. Commits(ctx)
  131. return
  132. }
  133. branchName := ctx.Repo.BranchName
  134. commitsCount, err := ctx.Repo.GitRepo.FileCommitsCount(branchName, fileName)
  135. if err != nil {
  136. ctx.Handle(500, "FileCommitsCount", err)
  137. return
  138. } else if commitsCount == 0 {
  139. ctx.Handle(404, "FileCommitsCount", nil)
  140. return
  141. }
  142. page := ctx.QueryInt("page")
  143. if page <= 1 {
  144. page = 1
  145. }
  146. ctx.Data["Page"] = paginater.New(int(commitsCount), git.CommitsRangeSize, page, 5)
  147. commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(branchName, fileName, page)
  148. if err != nil {
  149. ctx.Handle(500, "CommitsByFileAndRange", err)
  150. return
  151. }
  152. commits = renderIssueLinks(commits, ctx.Repo.RepoLink)
  153. commits = models.ValidateCommitsWithEmails(commits)
  154. commits = models.ParseCommitsWithSignature(commits)
  155. commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
  156. ctx.Data["Commits"] = commits
  157. ctx.Data["Username"] = ctx.Repo.Owner.Name
  158. ctx.Data["Reponame"] = ctx.Repo.Repository.Name
  159. ctx.Data["FileName"] = fileName
  160. ctx.Data["CommitCount"] = commitsCount
  161. ctx.Data["Branch"] = branchName
  162. ctx.HTML(200, tplCommits)
  163. }
  164. // Diff show different from current commit to previous commit
  165. func Diff(ctx *context.Context) {
  166. ctx.Data["PageIsDiff"] = true
  167. ctx.Data["RequireHighlightJS"] = true
  168. userName := ctx.Repo.Owner.Name
  169. repoName := ctx.Repo.Repository.Name
  170. commitID := ctx.Params(":sha")
  171. commit, err := ctx.Repo.GitRepo.GetCommit(commitID)
  172. if err != nil {
  173. if git.IsErrNotExist(err) {
  174. ctx.Handle(404, "Repo.GitRepo.GetCommit", err)
  175. } else {
  176. ctx.Handle(500, "Repo.GitRepo.GetCommit", err)
  177. }
  178. return
  179. }
  180. if len(commitID) != 40 {
  181. commitID = commit.ID.String()
  182. }
  183. statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository, ctx.Repo.Commit.ID.String(), 0)
  184. if err != nil {
  185. log.Error(3, "GetLatestCommitStatus: %v", err)
  186. }
  187. ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
  188. diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName),
  189. commitID, setting.Git.MaxGitDiffLines,
  190. setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
  191. if err != nil {
  192. ctx.Handle(404, "GetDiffCommit", err)
  193. return
  194. }
  195. parents := make([]string, commit.ParentCount())
  196. for i := 0; i < commit.ParentCount(); i++ {
  197. sha, err := commit.ParentID(i)
  198. parents[i] = sha.String()
  199. if err != nil {
  200. ctx.Handle(404, "repo.Diff", err)
  201. return
  202. }
  203. }
  204. ctx.Data["CommitID"] = commitID
  205. ctx.Data["Username"] = userName
  206. ctx.Data["Reponame"] = repoName
  207. ctx.Data["IsImageFile"] = commit.IsImageFile
  208. ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
  209. ctx.Data["Commit"] = commit
  210. ctx.Data["Verification"] = models.ParseCommitWithSignature(commit)
  211. ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
  212. ctx.Data["Diff"] = diff
  213. ctx.Data["Parents"] = parents
  214. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  215. ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", commitID)
  216. if commit.ParentCount() > 0 {
  217. ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", parents[0])
  218. }
  219. ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", commitID)
  220. ctx.HTML(200, tplDiff)
  221. }
  222. // RawDiff dumps diff results of repository in given commit ID to io.Writer
  223. func RawDiff(ctx *context.Context) {
  224. if err := models.GetRawDiff(
  225. models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name),
  226. ctx.Params(":sha"),
  227. models.RawDiffType(ctx.Params(":ext")),
  228. ctx.Resp,
  229. ); err != nil {
  230. ctx.Handle(500, "GetRawDiff", err)
  231. return
  232. }
  233. }
  234. // CompareDiff show different from one commit to another commit
  235. func CompareDiff(ctx *context.Context) {
  236. ctx.Data["IsRepoToolbarCommits"] = true
  237. ctx.Data["IsDiffCompare"] = true
  238. userName := ctx.Repo.Owner.Name
  239. repoName := ctx.Repo.Repository.Name
  240. beforeCommitID := ctx.Params(":before")
  241. afterCommitID := ctx.Params(":after")
  242. commit, err := ctx.Repo.GitRepo.GetCommit(afterCommitID)
  243. if err != nil {
  244. ctx.Handle(404, "GetCommit", err)
  245. return
  246. }
  247. diff, err := models.GetDiffRange(models.RepoPath(userName, repoName), beforeCommitID,
  248. afterCommitID, setting.Git.MaxGitDiffLines,
  249. setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
  250. if err != nil {
  251. ctx.Handle(404, "GetDiffRange", err)
  252. return
  253. }
  254. commits, err := commit.CommitsBeforeUntil(beforeCommitID)
  255. if err != nil {
  256. ctx.Handle(500, "CommitsBeforeUntil", err)
  257. return
  258. }
  259. commits = models.ValidateCommitsWithEmails(commits)
  260. commits = models.ParseCommitsWithSignature(commits)
  261. commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
  262. ctx.Data["CommitRepoLink"] = ctx.Repo.RepoLink
  263. ctx.Data["Commits"] = commits
  264. ctx.Data["CommitCount"] = commits.Len()
  265. ctx.Data["BeforeCommitID"] = beforeCommitID
  266. ctx.Data["AfterCommitID"] = afterCommitID
  267. ctx.Data["Username"] = userName
  268. ctx.Data["Reponame"] = repoName
  269. ctx.Data["IsImageFile"] = commit.IsImageFile
  270. ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID) + " · " + userName + "/" + repoName
  271. ctx.Data["Commit"] = commit
  272. ctx.Data["Diff"] = diff
  273. ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
  274. ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", afterCommitID)
  275. ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", beforeCommitID)
  276. ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", afterCommitID)
  277. ctx.Data["RequireHighlightJS"] = true
  278. ctx.HTML(200, tplDiff)
  279. }