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 11 kB

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