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