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