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.6 kB

11 years ago
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
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. "fmt"
  7. "os"
  8. "path"
  9. "strings"
  10. "github.com/Unknwon/com"
  11. "code.gitea.io/git"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/auth"
  14. "code.gitea.io/gitea/modules/base"
  15. "code.gitea.io/gitea/modules/context"
  16. "code.gitea.io/gitea/modules/log"
  17. "code.gitea.io/gitea/modules/setting"
  18. )
  19. const (
  20. tplCreate base.TplName = "repo/create"
  21. tplMigrate base.TplName = "repo/migrate"
  22. )
  23. // MustBeNotBare render when a repo is a bare git dir
  24. func MustBeNotBare(ctx *context.Context) {
  25. if ctx.Repo.Repository.IsBare {
  26. ctx.Handle(404, "MustBeNotBare", nil)
  27. }
  28. }
  29. func checkContextUser(ctx *context.Context, uid int64) *models.User {
  30. orgs, err := models.GetOwnedOrgsByUserIDDesc(ctx.User.ID, "updated_unix")
  31. if err != nil {
  32. ctx.Handle(500, "GetOwnedOrgsByUserIDDesc", err)
  33. return nil
  34. }
  35. ctx.Data["Orgs"] = orgs
  36. // Not equal means current user is an organization.
  37. if uid == ctx.User.ID || uid == 0 {
  38. return ctx.User
  39. }
  40. org, err := models.GetUserByID(uid)
  41. if models.IsErrUserNotExist(err) {
  42. return ctx.User
  43. }
  44. if err != nil {
  45. ctx.Handle(500, "GetUserByID", fmt.Errorf("[%d]: %v", uid, err))
  46. return nil
  47. }
  48. // Check ownership of organization.
  49. if !org.IsOrganization() || !(ctx.User.IsAdmin || org.IsOwnedBy(ctx.User.ID)) {
  50. ctx.Error(403)
  51. return nil
  52. }
  53. return org
  54. }
  55. // Create render creating repository page
  56. func Create(ctx *context.Context) {
  57. ctx.Data["Title"] = ctx.Tr("new_repo")
  58. // Give default value for template to render.
  59. ctx.Data["Gitignores"] = models.Gitignores
  60. ctx.Data["Licenses"] = models.Licenses
  61. ctx.Data["Readmes"] = models.Readmes
  62. ctx.Data["readme"] = "Default"
  63. ctx.Data["private"] = ctx.User.LastRepoVisibility
  64. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  65. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  66. if ctx.Written() {
  67. return
  68. }
  69. ctx.Data["ContextUser"] = ctxUser
  70. ctx.HTML(200, tplCreate)
  71. }
  72. func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) {
  73. switch {
  74. case models.IsErrReachLimitOfRepo(err):
  75. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.RepoCreationNum()), tpl, form)
  76. case models.IsErrRepoAlreadyExist(err):
  77. ctx.Data["Err_RepoName"] = true
  78. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
  79. case models.IsErrNameReserved(err):
  80. ctx.Data["Err_RepoName"] = true
  81. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
  82. case models.IsErrNamePatternNotAllowed(err):
  83. ctx.Data["Err_RepoName"] = true
  84. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
  85. default:
  86. ctx.Handle(500, name, err)
  87. }
  88. }
  89. // CreatePost response for creating repository
  90. func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
  91. ctx.Data["Title"] = ctx.Tr("new_repo")
  92. ctx.Data["Gitignores"] = models.Gitignores
  93. ctx.Data["Licenses"] = models.Licenses
  94. ctx.Data["Readmes"] = models.Readmes
  95. ctxUser := checkContextUser(ctx, form.UID)
  96. if ctx.Written() {
  97. return
  98. }
  99. ctx.Data["ContextUser"] = ctxUser
  100. if ctx.HasError() {
  101. ctx.HTML(200, tplCreate)
  102. return
  103. }
  104. repo, err := models.CreateRepository(ctxUser, models.CreateRepoOptions{
  105. Name: form.RepoName,
  106. Description: form.Description,
  107. Gitignores: form.Gitignores,
  108. License: form.License,
  109. Readme: form.Readme,
  110. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  111. AutoInit: form.AutoInit,
  112. })
  113. if err == nil {
  114. log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
  115. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
  116. return
  117. }
  118. if repo != nil {
  119. if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
  120. log.Error(4, "DeleteRepository: %v", errDelete)
  121. }
  122. }
  123. handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
  124. }
  125. // Migrate render migration of repository page
  126. func Migrate(ctx *context.Context) {
  127. ctx.Data["Title"] = ctx.Tr("new_migrate")
  128. ctx.Data["private"] = ctx.User.LastRepoVisibility
  129. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  130. ctx.Data["mirror"] = ctx.Query("mirror") == "1"
  131. ctx.Data["LFSActive"] = setting.LFS.StartServer
  132. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  133. if ctx.Written() {
  134. return
  135. }
  136. ctx.Data["ContextUser"] = ctxUser
  137. ctx.HTML(200, tplMigrate)
  138. }
  139. // MigratePost response for migrating from external git repository
  140. func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
  141. ctx.Data["Title"] = ctx.Tr("new_migrate")
  142. ctxUser := checkContextUser(ctx, form.UID)
  143. if ctx.Written() {
  144. return
  145. }
  146. ctx.Data["ContextUser"] = ctxUser
  147. if ctx.HasError() {
  148. ctx.HTML(200, tplMigrate)
  149. return
  150. }
  151. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  152. if err != nil {
  153. if models.IsErrInvalidCloneAddr(err) {
  154. ctx.Data["Err_CloneAddr"] = true
  155. addrErr := err.(models.ErrInvalidCloneAddr)
  156. switch {
  157. case addrErr.IsURLError:
  158. ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form)
  159. case addrErr.IsPermissionDenied:
  160. ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form)
  161. case addrErr.IsInvalidPath:
  162. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form)
  163. default:
  164. ctx.Handle(500, "Unknown error", err)
  165. }
  166. } else {
  167. ctx.Handle(500, "ParseRemoteAddr", err)
  168. }
  169. return
  170. }
  171. repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
  172. Name: form.RepoName,
  173. Description: form.Description,
  174. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  175. IsMirror: form.Mirror,
  176. RemoteAddr: remoteAddr,
  177. })
  178. if err == nil {
  179. log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName)
  180. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName)
  181. return
  182. }
  183. if repo != nil {
  184. if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
  185. log.Error(4, "DeleteRepository: %v", errDelete)
  186. }
  187. }
  188. if strings.Contains(err.Error(), "Authentication failed") ||
  189. strings.Contains(err.Error(), "could not read Username") {
  190. ctx.Data["Err_Auth"] = true
  191. ctx.RenderWithErr(ctx.Tr("form.auth_failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form)
  192. return
  193. } else if strings.Contains(err.Error(), "fatal:") {
  194. ctx.Data["Err_CloneAddr"] = true
  195. ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form)
  196. return
  197. }
  198. handleCreateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
  199. }
  200. // Action response for actions to a repository
  201. func Action(ctx *context.Context) {
  202. var err error
  203. switch ctx.Params(":action") {
  204. case "watch":
  205. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  206. case "unwatch":
  207. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  208. case "star":
  209. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  210. case "unstar":
  211. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  212. case "desc": // FIXME: this is not used
  213. if !ctx.Repo.IsOwner() {
  214. ctx.Error(404)
  215. return
  216. }
  217. ctx.Repo.Repository.Description = ctx.Query("desc")
  218. ctx.Repo.Repository.Website = ctx.Query("site")
  219. err = models.UpdateRepository(ctx.Repo.Repository, false)
  220. }
  221. if err != nil {
  222. ctx.Handle(500, fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  223. return
  224. }
  225. redirectTo := ctx.Query("redirect_to")
  226. if len(redirectTo) == 0 {
  227. redirectTo = ctx.Repo.RepoLink
  228. }
  229. ctx.Redirect(redirectTo)
  230. }
  231. // Download download an archive of a repository
  232. func Download(ctx *context.Context) {
  233. var (
  234. uri = ctx.Params("*")
  235. refName string
  236. ext string
  237. archivePath string
  238. archiveType git.ArchiveType
  239. )
  240. switch {
  241. case strings.HasSuffix(uri, ".zip"):
  242. ext = ".zip"
  243. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  244. archiveType = git.ZIP
  245. case strings.HasSuffix(uri, ".tar.gz"):
  246. ext = ".tar.gz"
  247. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  248. archiveType = git.TARGZ
  249. default:
  250. log.Trace("Unknown format: %s", uri)
  251. ctx.Error(404)
  252. return
  253. }
  254. refName = strings.TrimSuffix(uri, ext)
  255. if !com.IsDir(archivePath) {
  256. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  257. ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err)
  258. return
  259. }
  260. }
  261. // Get corresponding commit.
  262. var (
  263. commit *git.Commit
  264. err error
  265. )
  266. gitRepo := ctx.Repo.GitRepo
  267. if gitRepo.IsBranchExist(refName) {
  268. commit, err = gitRepo.GetBranchCommit(refName)
  269. if err != nil {
  270. ctx.Handle(500, "GetBranchCommit", err)
  271. return
  272. }
  273. } else if gitRepo.IsTagExist(refName) {
  274. commit, err = gitRepo.GetTagCommit(refName)
  275. if err != nil {
  276. ctx.Handle(500, "GetTagCommit", err)
  277. return
  278. }
  279. } else if len(refName) >= 4 && len(refName) <= 40 {
  280. commit, err = gitRepo.GetCommit(refName)
  281. if err != nil {
  282. ctx.Handle(404, "GetCommit", nil)
  283. return
  284. }
  285. } else {
  286. ctx.Handle(404, "Download", nil)
  287. return
  288. }
  289. archivePath = path.Join(archivePath, base.ShortSha(commit.ID.String())+ext)
  290. if !com.IsFile(archivePath) {
  291. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  292. ctx.Handle(500, "Download -> CreateArchive "+archivePath, err)
  293. return
  294. }
  295. }
  296. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext)
  297. }