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.

repo.go 9.8 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 middleware
  5. import (
  6. "fmt"
  7. "path"
  8. "strings"
  9. "gopkg.in/macaron.v1"
  10. "github.com/gogits/git-module"
  11. "github.com/gogits/gogs/models"
  12. "github.com/gogits/gogs/modules/log"
  13. "github.com/gogits/gogs/modules/setting"
  14. )
  15. func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
  16. // Non-fork repository will not return error in this method.
  17. if err := repo.GetBaseRepo(); err != nil {
  18. if models.IsErrRepoNotExist(err) {
  19. repo.IsFork = false
  20. repo.ForkID = 0
  21. return
  22. }
  23. ctx.Handle(500, "GetBaseRepo", err)
  24. return
  25. } else if err = repo.BaseRepo.GetOwner(); err != nil {
  26. ctx.Handle(500, "BaseRepo.GetOwner", err)
  27. return
  28. }
  29. }
  30. func RepoAssignment(args ...bool) macaron.Handler {
  31. return func(ctx *Context) {
  32. var (
  33. displayBare bool // To display bare page if it is a bare repo.
  34. )
  35. if len(args) >= 1 {
  36. displayBare = args[0]
  37. }
  38. var (
  39. owner *models.User
  40. err error
  41. )
  42. userName := ctx.Params(":username")
  43. repoName := ctx.Params(":reponame")
  44. refName := ctx.Params(":branchname")
  45. if len(refName) == 0 {
  46. refName = ctx.Params(":path")
  47. }
  48. // Check if the user is the same as the repository owner
  49. if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
  50. owner = ctx.User
  51. } else {
  52. owner, err = models.GetUserByName(userName)
  53. if err != nil {
  54. if models.IsErrUserNotExist(err) {
  55. ctx.Handle(404, "GetUserByName", err)
  56. } else {
  57. ctx.Handle(500, "GetUserByName", err)
  58. }
  59. return
  60. }
  61. }
  62. ctx.Repo.Owner = owner
  63. // Get repository.
  64. repo, err := models.GetRepositoryByName(owner.Id, repoName)
  65. if err != nil {
  66. if models.IsErrRepoNotExist(err) {
  67. ctx.Handle(404, "GetRepositoryByName", err)
  68. } else {
  69. ctx.Handle(500, "GetRepositoryByName", err)
  70. }
  71. return
  72. } else if err = repo.GetOwner(); err != nil {
  73. ctx.Handle(500, "GetOwner", err)
  74. return
  75. }
  76. // Admin has super access.
  77. if ctx.IsSigned && ctx.User.IsAdmin {
  78. ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
  79. } else {
  80. mode, err := models.AccessLevel(ctx.User, repo)
  81. if err != nil {
  82. ctx.Handle(500, "AccessLevel", err)
  83. return
  84. }
  85. ctx.Repo.AccessMode = mode
  86. }
  87. // Check access.
  88. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
  89. ctx.Handle(404, "no access right", err)
  90. return
  91. }
  92. ctx.Data["HasAccess"] = true
  93. if repo.IsMirror {
  94. ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
  95. if err != nil {
  96. ctx.Handle(500, "GetMirror", err)
  97. return
  98. }
  99. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  100. ctx.Data["Mirror"] = ctx.Repo.Mirror
  101. }
  102. ctx.Repo.Repository = repo
  103. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  104. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  105. if err != nil {
  106. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  107. return
  108. }
  109. ctx.Repo.GitRepo = gitRepo
  110. ctx.Repo.RepoLink = repo.RepoLink()
  111. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  112. ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
  113. tags, err := ctx.Repo.GitRepo.GetTags()
  114. if err != nil {
  115. ctx.Handle(500, "GetTags", err)
  116. return
  117. }
  118. ctx.Data["Tags"] = tags
  119. ctx.Repo.Repository.NumTags = len(tags)
  120. ctx.Data["Title"] = owner.Name + "/" + repo.Name
  121. ctx.Data["Repository"] = repo
  122. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  123. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
  124. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
  125. ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter()
  126. if repo.IsFork {
  127. RetrieveBaseRepo(ctx, repo)
  128. if ctx.Written() {
  129. return
  130. }
  131. }
  132. // People who have push access and propose a new pull request.
  133. if ctx.Repo.IsWriter() {
  134. // Pull request is allowed if this is a fork repository
  135. // and base repository accepts pull requests.
  136. if repo.BaseRepo != nil {
  137. if repo.BaseRepo.AllowsPulls() {
  138. ctx.Data["CanPullRequest"] = true
  139. ctx.Data["BaseRepo"] = repo.BaseRepo
  140. }
  141. } else {
  142. // Or, this is repository accepts pull requests between branches.
  143. if repo.AllowsPulls() {
  144. ctx.Data["CanPullRequest"] = true
  145. ctx.Data["BaseRepo"] = repo
  146. ctx.Data["IsBetweenBranches"] = true
  147. }
  148. }
  149. }
  150. ctx.Data["DisableSSH"] = setting.SSH.Disabled
  151. ctx.Data["CloneLink"] = repo.CloneLink()
  152. ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
  153. if ctx.IsSigned {
  154. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
  155. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
  156. }
  157. // repo is bare and display enable
  158. if ctx.Repo.Repository.IsBare {
  159. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  160. // NOTE: to prevent templating error
  161. ctx.Data["BranchName"] = ""
  162. if displayBare {
  163. if !ctx.Repo.IsAdmin() {
  164. ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
  165. }
  166. ctx.HTML(200, "repo/bare")
  167. }
  168. return
  169. }
  170. ctx.Data["TagName"] = ctx.Repo.TagName
  171. brs, err := ctx.Repo.GitRepo.GetBranches()
  172. if err != nil {
  173. ctx.Handle(500, "GetBranches", err)
  174. return
  175. }
  176. ctx.Data["Branches"] = brs
  177. ctx.Data["BrancheCount"] = len(brs)
  178. // If not branch selected, try default one.
  179. // If default branch doesn't exists, fall back to some other branch.
  180. if len(ctx.Repo.BranchName) == 0 {
  181. if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  182. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  183. } else if len(brs) > 0 {
  184. ctx.Repo.BranchName = brs[0]
  185. }
  186. }
  187. ctx.Data["BranchName"] = ctx.Repo.BranchName
  188. ctx.Data["CommitID"] = ctx.Repo.CommitID
  189. if ctx.Query("go-get") == "1" {
  190. ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
  191. prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)
  192. ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
  193. ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
  194. }
  195. }
  196. }
  197. // RepoRef handles repository reference name including those contain `/`.
  198. func RepoRef() macaron.Handler {
  199. return func(ctx *Context) {
  200. // Empty repository does not have reference information.
  201. if ctx.Repo.Repository.IsBare {
  202. return
  203. }
  204. var (
  205. refName string
  206. err error
  207. )
  208. // For API calls.
  209. if ctx.Repo.GitRepo == nil {
  210. repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  211. gitRepo, err := git.OpenRepository(repoPath)
  212. if err != nil {
  213. ctx.Handle(500, "RepoRef Invalid repo "+repoPath, err)
  214. return
  215. }
  216. ctx.Repo.GitRepo = gitRepo
  217. }
  218. // Get default branch.
  219. if len(ctx.Params("*")) == 0 {
  220. refName = ctx.Repo.Repository.DefaultBranch
  221. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  222. brs, err := ctx.Repo.GitRepo.GetBranches()
  223. if err != nil {
  224. ctx.Handle(500, "GetBranches", err)
  225. return
  226. }
  227. refName = brs[0]
  228. }
  229. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
  230. if err != nil {
  231. ctx.Handle(500, "GetBranchCommit", err)
  232. return
  233. }
  234. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  235. ctx.Repo.IsViewBranch = true
  236. } else {
  237. hasMatched := false
  238. parts := strings.Split(ctx.Params("*"), "/")
  239. for i, part := range parts {
  240. refName = strings.TrimPrefix(refName+"/"+part, "/")
  241. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  242. ctx.Repo.GitRepo.IsTagExist(refName) {
  243. if i < len(parts)-1 {
  244. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  245. }
  246. hasMatched = true
  247. break
  248. }
  249. }
  250. if !hasMatched && len(parts[0]) == 40 {
  251. refName = parts[0]
  252. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  253. }
  254. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  255. ctx.Repo.IsViewBranch = true
  256. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
  257. if err != nil {
  258. ctx.Handle(500, "GetBranchCommit", err)
  259. return
  260. }
  261. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  262. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  263. ctx.Repo.IsViewTag = true
  264. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
  265. if err != nil {
  266. ctx.Handle(500, "GetTagCommit", err)
  267. return
  268. }
  269. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  270. } else if len(refName) == 40 {
  271. ctx.Repo.IsViewCommit = true
  272. ctx.Repo.CommitID = refName
  273. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  274. if err != nil {
  275. ctx.Handle(404, "GetCommit", nil)
  276. return
  277. }
  278. } else {
  279. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  280. return
  281. }
  282. }
  283. ctx.Repo.BranchName = refName
  284. ctx.Data["BranchName"] = ctx.Repo.BranchName
  285. ctx.Data["CommitID"] = ctx.Repo.CommitID
  286. ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
  287. ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
  288. ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
  289. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  290. if err != nil {
  291. ctx.Handle(500, "CommitsCount", err)
  292. return
  293. }
  294. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  295. }
  296. }
  297. func RequireRepoAdmin() macaron.Handler {
  298. return func(ctx *Context) {
  299. if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) {
  300. ctx.Handle(404, ctx.Req.RequestURI, nil)
  301. return
  302. }
  303. }
  304. }
  305. func RequireRepoWriter() macaron.Handler {
  306. return func(ctx *Context) {
  307. if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
  308. ctx.Handle(404, ctx.Req.RequestURI, nil)
  309. return
  310. }
  311. }
  312. }
  313. // GitHookService checks if repository Git hooks service has been enabled.
  314. func GitHookService() macaron.Handler {
  315. return func(ctx *Context) {
  316. if !ctx.User.CanEditGitHook() {
  317. ctx.Handle(404, "GitHookService", nil)
  318. return
  319. }
  320. }
  321. }