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.5 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
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  132. if ctx.Written() {
  133. return
  134. }
  135. ctx.Data["ContextUser"] = ctxUser
  136. ctx.HTML(200, tplMigrate)
  137. }
  138. // MigratePost response for migrating from external git repository
  139. func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
  140. ctx.Data["Title"] = ctx.Tr("new_migrate")
  141. ctxUser := checkContextUser(ctx, form.UID)
  142. if ctx.Written() {
  143. return
  144. }
  145. ctx.Data["ContextUser"] = ctxUser
  146. if ctx.HasError() {
  147. ctx.HTML(200, tplMigrate)
  148. return
  149. }
  150. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  151. if err != nil {
  152. if models.IsErrInvalidCloneAddr(err) {
  153. ctx.Data["Err_CloneAddr"] = true
  154. addrErr := err.(models.ErrInvalidCloneAddr)
  155. switch {
  156. case addrErr.IsURLError:
  157. ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form)
  158. case addrErr.IsPermissionDenied:
  159. ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form)
  160. case addrErr.IsInvalidPath:
  161. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form)
  162. default:
  163. ctx.Handle(500, "Unknown error", err)
  164. }
  165. } else {
  166. ctx.Handle(500, "ParseRemoteAddr", err)
  167. }
  168. return
  169. }
  170. repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
  171. Name: form.RepoName,
  172. Description: form.Description,
  173. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  174. IsMirror: form.Mirror,
  175. RemoteAddr: remoteAddr,
  176. })
  177. if err == nil {
  178. log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName)
  179. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
  180. return
  181. }
  182. if repo != nil {
  183. if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
  184. log.Error(4, "DeleteRepository: %v", errDelete)
  185. }
  186. }
  187. if strings.Contains(err.Error(), "Authentication failed") ||
  188. strings.Contains(err.Error(), "could not read Username") {
  189. ctx.Data["Err_Auth"] = true
  190. ctx.RenderWithErr(ctx.Tr("form.auth_failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form)
  191. return
  192. } else if strings.Contains(err.Error(), "fatal:") {
  193. ctx.Data["Err_CloneAddr"] = true
  194. ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form)
  195. return
  196. }
  197. handleCreateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
  198. }
  199. // Action response for actions to a repository
  200. func Action(ctx *context.Context) {
  201. var err error
  202. switch ctx.Params(":action") {
  203. case "watch":
  204. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  205. case "unwatch":
  206. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  207. case "star":
  208. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  209. case "unstar":
  210. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  211. case "desc": // FIXME: this is not used
  212. if !ctx.Repo.IsOwner() {
  213. ctx.Error(404)
  214. return
  215. }
  216. ctx.Repo.Repository.Description = ctx.Query("desc")
  217. ctx.Repo.Repository.Website = ctx.Query("site")
  218. err = models.UpdateRepository(ctx.Repo.Repository, false)
  219. }
  220. if err != nil {
  221. ctx.Handle(500, fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  222. return
  223. }
  224. redirectTo := ctx.Query("redirect_to")
  225. if len(redirectTo) == 0 {
  226. redirectTo = ctx.Repo.RepoLink
  227. }
  228. ctx.Redirect(redirectTo)
  229. }
  230. // Download download an archive of a repository
  231. func Download(ctx *context.Context) {
  232. var (
  233. uri = ctx.Params("*")
  234. refName string
  235. ext string
  236. archivePath string
  237. archiveType git.ArchiveType
  238. )
  239. switch {
  240. case strings.HasSuffix(uri, ".zip"):
  241. ext = ".zip"
  242. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  243. archiveType = git.ZIP
  244. case strings.HasSuffix(uri, ".tar.gz"):
  245. ext = ".tar.gz"
  246. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  247. archiveType = git.TARGZ
  248. default:
  249. log.Trace("Unknown format: %s", uri)
  250. ctx.Error(404)
  251. return
  252. }
  253. refName = strings.TrimSuffix(uri, ext)
  254. if !com.IsDir(archivePath) {
  255. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  256. ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err)
  257. return
  258. }
  259. }
  260. // Get corresponding commit.
  261. var (
  262. commit *git.Commit
  263. err error
  264. )
  265. gitRepo := ctx.Repo.GitRepo
  266. if gitRepo.IsBranchExist(refName) {
  267. commit, err = gitRepo.GetBranchCommit(refName)
  268. if err != nil {
  269. ctx.Handle(500, "GetBranchCommit", err)
  270. return
  271. }
  272. } else if gitRepo.IsTagExist(refName) {
  273. commit, err = gitRepo.GetTagCommit(refName)
  274. if err != nil {
  275. ctx.Handle(500, "GetTagCommit", err)
  276. return
  277. }
  278. } else if len(refName) >= 4 && len(refName) <= 40 {
  279. commit, err = gitRepo.GetCommit(refName)
  280. if err != nil {
  281. ctx.Handle(404, "GetCommit", nil)
  282. return
  283. }
  284. } else {
  285. ctx.Handle(404, "Download", nil)
  286. return
  287. }
  288. archivePath = path.Join(archivePath, base.ShortSha(commit.ID.String())+ext)
  289. if !com.IsFile(archivePath) {
  290. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  291. ctx.Handle(500, "Download -> CreateArchive "+archivePath, err)
  292. return
  293. }
  294. }
  295. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext)
  296. }