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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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["MirrorInterval"] = ctx.Repo.Mirror.Interval
  143. ctx.Data["Mirror"] = ctx.Repo.Mirror
  144. }
  145. ctx.Repo.Repository = repo
  146. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  147. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  148. if err != nil {
  149. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  150. return
  151. }
  152. ctx.Repo.GitRepo = gitRepo
  153. ctx.Repo.RepoLink = repo.RepoLink()
  154. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  155. ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
  156. tags, err := ctx.Repo.GitRepo.GetTags()
  157. if err != nil {
  158. ctx.Handle(500, "GetTags", err)
  159. return
  160. }
  161. ctx.Data["Tags"] = tags
  162. ctx.Repo.Repository.NumTags = len(tags)
  163. ctx.Data["Title"] = owner.Name + "/" + repo.Name
  164. ctx.Data["Repository"] = repo
  165. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  166. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
  167. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
  168. ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter()
  169. ctx.Data["DisableSSH"] = setting.SSH.Disabled
  170. ctx.Data["CloneLink"] = repo.CloneLink()
  171. ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
  172. if ctx.IsSigned {
  173. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
  174. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
  175. }
  176. // repo is bare and display enable
  177. if ctx.Repo.Repository.IsBare {
  178. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  179. // NOTE: to prevent templating error
  180. ctx.Data["BranchName"] = ""
  181. if displayBare {
  182. if !ctx.Repo.IsAdmin() {
  183. ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
  184. }
  185. ctx.HTML(200, "repo/bare")
  186. }
  187. return
  188. }
  189. ctx.Data["TagName"] = ctx.Repo.TagName
  190. brs, err := ctx.Repo.GitRepo.GetBranches()
  191. if err != nil {
  192. ctx.Handle(500, "GetBranches", err)
  193. return
  194. }
  195. ctx.Data["Branches"] = brs
  196. ctx.Data["BrancheCount"] = len(brs)
  197. // If not branch selected, try default one.
  198. // If default branch doesn't exists, fall back to some other branch.
  199. if len(ctx.Repo.BranchName) == 0 {
  200. if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  201. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  202. } else if len(brs) > 0 {
  203. ctx.Repo.BranchName = brs[0]
  204. }
  205. }
  206. ctx.Data["BranchName"] = ctx.Repo.BranchName
  207. ctx.Data["CommitID"] = ctx.Repo.CommitID
  208. if repo.IsFork {
  209. RetrieveBaseRepo(ctx, repo)
  210. if ctx.Written() {
  211. return
  212. }
  213. }
  214. // People who have push access and propose a new pull request.
  215. if ctx.Repo.IsWriter() {
  216. // Pull request is allowed if this is a fork repository
  217. // and base repository accepts pull requests.
  218. if repo.BaseRepo != nil {
  219. if repo.BaseRepo.AllowsPulls() {
  220. ctx.Data["BaseRepo"] = repo.BaseRepo
  221. ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
  222. ctx.Repo.PullRequest.Allowed = true
  223. ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName
  224. }
  225. } else {
  226. // Or, this is repository accepts pull requests between branches.
  227. if repo.AllowsPulls() {
  228. ctx.Data["BaseRepo"] = repo
  229. ctx.Repo.PullRequest.BaseRepo = repo
  230. ctx.Repo.PullRequest.Allowed = true
  231. ctx.Repo.PullRequest.SameRepo = true
  232. ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName
  233. }
  234. }
  235. }
  236. ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
  237. if ctx.Query("go-get") == "1" {
  238. ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
  239. prefix := setting.AppUrl + path.Join(owner.Name, repo.Name, "src", ctx.Repo.BranchName)
  240. ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
  241. ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
  242. }
  243. }
  244. }
  245. // RepoRef handles repository reference name including those contain `/`.
  246. func RepoRef() macaron.Handler {
  247. return func(ctx *Context) {
  248. // Empty repository does not have reference information.
  249. if ctx.Repo.Repository.IsBare {
  250. return
  251. }
  252. var (
  253. refName string
  254. err error
  255. )
  256. // For API calls.
  257. if ctx.Repo.GitRepo == nil {
  258. repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  259. gitRepo, err := git.OpenRepository(repoPath)
  260. if err != nil {
  261. ctx.Handle(500, "RepoRef Invalid repo "+repoPath, err)
  262. return
  263. }
  264. ctx.Repo.GitRepo = gitRepo
  265. }
  266. // Get default branch.
  267. if len(ctx.Params("*")) == 0 {
  268. refName = ctx.Repo.Repository.DefaultBranch
  269. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  270. brs, err := ctx.Repo.GitRepo.GetBranches()
  271. if err != nil {
  272. ctx.Handle(500, "GetBranches", err)
  273. return
  274. }
  275. refName = brs[0]
  276. }
  277. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
  278. if err != nil {
  279. ctx.Handle(500, "GetBranchCommit", err)
  280. return
  281. }
  282. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  283. ctx.Repo.IsViewBranch = true
  284. } else {
  285. hasMatched := false
  286. parts := strings.Split(ctx.Params("*"), "/")
  287. for i, part := range parts {
  288. refName = strings.TrimPrefix(refName+"/"+part, "/")
  289. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  290. ctx.Repo.GitRepo.IsTagExist(refName) {
  291. if i < len(parts)-1 {
  292. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  293. }
  294. hasMatched = true
  295. break
  296. }
  297. }
  298. if !hasMatched && len(parts[0]) == 40 {
  299. refName = parts[0]
  300. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  301. }
  302. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  303. ctx.Repo.IsViewBranch = true
  304. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
  305. if err != nil {
  306. ctx.Handle(500, "GetBranchCommit", err)
  307. return
  308. }
  309. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  310. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  311. ctx.Repo.IsViewTag = true
  312. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
  313. if err != nil {
  314. ctx.Handle(500, "GetTagCommit", err)
  315. return
  316. }
  317. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  318. } else if len(refName) == 40 {
  319. ctx.Repo.IsViewCommit = true
  320. ctx.Repo.CommitID = refName
  321. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  322. if err != nil {
  323. ctx.Handle(404, "GetCommit", nil)
  324. return
  325. }
  326. } else {
  327. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  328. return
  329. }
  330. }
  331. ctx.Repo.BranchName = refName
  332. ctx.Data["BranchName"] = ctx.Repo.BranchName
  333. ctx.Data["CommitID"] = ctx.Repo.CommitID
  334. ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
  335. ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
  336. ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
  337. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  338. if err != nil {
  339. ctx.Handle(500, "CommitsCount", err)
  340. return
  341. }
  342. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  343. }
  344. }
  345. func RequireRepoAdmin() macaron.Handler {
  346. return func(ctx *Context) {
  347. if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) {
  348. ctx.Handle(404, ctx.Req.RequestURI, nil)
  349. return
  350. }
  351. }
  352. }
  353. func RequireRepoWriter() macaron.Handler {
  354. return func(ctx *Context) {
  355. if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
  356. ctx.Handle(404, ctx.Req.RequestURI, nil)
  357. return
  358. }
  359. }
  360. }
  361. // GitHookService checks if repository Git hooks service has been enabled.
  362. func GitHookService() macaron.Handler {
  363. return func(ctx *Context) {
  364. if !ctx.User.CanEditGitHook() {
  365. ctx.Handle(404, "GitHookService", nil)
  366. return
  367. }
  368. }
  369. }