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

11 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
11 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. "net/url"
  8. "os"
  9. "path"
  10. "strings"
  11. "github.com/Unknwon/com"
  12. "github.com/gogits/gogs/models"
  13. "github.com/gogits/gogs/modules/auth"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/git"
  16. "github.com/gogits/gogs/modules/log"
  17. "github.com/gogits/gogs/modules/middleware"
  18. "github.com/gogits/gogs/modules/setting"
  19. )
  20. const (
  21. CREATE base.TplName = "repo/create"
  22. MIGRATE base.TplName = "repo/migrate"
  23. FORK base.TplName = "repo/fork"
  24. )
  25. func checkContextUser(ctx *middleware.Context, uid int64) (*models.User, error) {
  26. ctxUser := ctx.User
  27. if uid > 0 {
  28. org, err := models.GetUserById(uid)
  29. if err != models.ErrUserNotExist {
  30. if err != nil {
  31. return nil, fmt.Errorf("GetUserById: %v", err)
  32. }
  33. ctxUser = org
  34. }
  35. }
  36. return ctxUser, nil
  37. }
  38. func Create(ctx *middleware.Context) {
  39. ctx.Data["Title"] = ctx.Tr("new_repo")
  40. // Give default value for template to render.
  41. ctx.Data["gitignore"] = "0"
  42. ctx.Data["license"] = "0"
  43. ctx.Data["Gitignores"] = models.Gitignores
  44. ctx.Data["Licenses"] = models.Licenses
  45. ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org"))
  46. if err != nil {
  47. ctx.Handle(500, "checkContextUser", err)
  48. return
  49. }
  50. ctx.Data["ContextUser"] = ctxUser
  51. if err := ctx.User.GetOrganizations(); err != nil {
  52. ctx.Handle(500, "GetOrganizations", err)
  53. return
  54. }
  55. ctx.Data["Orgs"] = ctx.User.Orgs
  56. ctx.HTML(200, CREATE)
  57. }
  58. func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
  59. ctx.Data["Title"] = ctx.Tr("new_repo")
  60. ctx.Data["Gitignores"] = models.Gitignores
  61. ctx.Data["Licenses"] = models.Licenses
  62. ctxUser := ctx.User
  63. // Not equal means current user is an organization.
  64. if form.Uid != ctx.User.Id {
  65. var err error
  66. ctxUser, err = checkContextUser(ctx, form.Uid)
  67. if err != nil {
  68. ctx.Handle(500, "checkContextUser", err)
  69. return
  70. }
  71. }
  72. ctx.Data["ContextUser"] = ctxUser
  73. if err := ctx.User.GetOrganizations(); err != nil {
  74. ctx.Handle(500, "GetOrganizations", err)
  75. return
  76. }
  77. ctx.Data["Orgs"] = ctx.User.Orgs
  78. if ctx.HasError() {
  79. ctx.HTML(200, CREATE)
  80. return
  81. }
  82. if ctxUser.IsOrganization() {
  83. // Check ownership of organization.
  84. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  85. ctx.Error(403)
  86. return
  87. }
  88. }
  89. repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description,
  90. form.Gitignore, form.License, form.Private, false, form.AutoInit)
  91. if err == nil {
  92. log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name)
  93. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  94. return
  95. } else if err == models.ErrRepoAlreadyExist {
  96. ctx.Data["Err_RepoName"] = true
  97. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), CREATE, &form)
  98. return
  99. } else if err == models.ErrRepoNameIllegal {
  100. ctx.Data["Err_RepoName"] = true
  101. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), CREATE, &form)
  102. return
  103. }
  104. if repo != nil {
  105. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  106. log.Error(4, "DeleteRepository: %v", errDelete)
  107. }
  108. }
  109. ctx.Handle(500, "CreatePost", err)
  110. }
  111. func Migrate(ctx *middleware.Context) {
  112. ctx.Data["Title"] = ctx.Tr("new_migrate")
  113. ctxUser, err := checkContextUser(ctx, ctx.QueryInt64("org"))
  114. if err != nil {
  115. ctx.Handle(500, "checkContextUser", err)
  116. return
  117. }
  118. ctx.Data["ContextUser"] = ctxUser
  119. if err := ctx.User.GetOrganizations(); err != nil {
  120. ctx.Handle(500, "GetOrganizations", err)
  121. return
  122. }
  123. ctx.Data["Orgs"] = ctx.User.Orgs
  124. ctx.HTML(200, MIGRATE)
  125. }
  126. func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
  127. ctx.Data["Title"] = ctx.Tr("new_migrate")
  128. ctxUser := ctx.User
  129. // Not equal means current user is an organization.
  130. if form.Uid != ctx.User.Id {
  131. var err error
  132. ctxUser, err = checkContextUser(ctx, form.Uid)
  133. if err != nil {
  134. ctx.Handle(500, "checkContextUser", err)
  135. return
  136. }
  137. }
  138. ctx.Data["ContextUser"] = ctxUser
  139. if err := ctx.User.GetOrganizations(); err != nil {
  140. ctx.Handle(500, "GetOrganizations", err)
  141. return
  142. }
  143. ctx.Data["Orgs"] = ctx.User.Orgs
  144. if ctx.HasError() {
  145. ctx.HTML(200, MIGRATE)
  146. return
  147. }
  148. if ctxUser.IsOrganization() {
  149. // Check ownership of organization.
  150. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  151. ctx.Error(403)
  152. return
  153. }
  154. }
  155. // Remote address can be HTTP/HTTPS URL or local path.
  156. remoteAddr := form.CloneAddr
  157. if strings.HasPrefix(form.CloneAddr, "http") {
  158. u, err := url.Parse(form.CloneAddr)
  159. if err != nil {
  160. ctx.Data["Err_CloneAddr"] = true
  161. ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
  162. return
  163. }
  164. if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 {
  165. u.User = url.UserPassword(form.AuthUsername, form.AuthPassword)
  166. }
  167. remoteAddr = u.String()
  168. } else if !com.IsDir(remoteAddr) {
  169. ctx.Data["Err_CloneAddr"] = true
  170. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form)
  171. return
  172. }
  173. repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr)
  174. if err == nil {
  175. log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
  176. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
  177. return
  178. } else if err == models.ErrRepoAlreadyExist {
  179. ctx.Data["Err_RepoName"] = true
  180. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), MIGRATE, &form)
  181. return
  182. } else if err == models.ErrRepoNameIllegal {
  183. ctx.Data["Err_RepoName"] = true
  184. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), MIGRATE, &form)
  185. return
  186. }
  187. if repo != nil {
  188. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  189. log.Error(4, "DeleteRepository: %v", errDelete)
  190. }
  191. }
  192. if strings.Contains(err.Error(), "Authentication failed") {
  193. ctx.Data["Err_Auth"] = true
  194. ctx.RenderWithErr(ctx.Tr("form.auth_failed", err), MIGRATE, &form)
  195. return
  196. }
  197. ctx.Handle(500, "MigratePost", err)
  198. }
  199. func getForkRepository(ctx *middleware.Context) (*models.Repository, error) {
  200. forkId := ctx.QueryInt64("fork_id")
  201. ctx.Data["ForkId"] = forkId
  202. forkRepo, err := models.GetRepositoryById(forkId)
  203. if err != nil {
  204. return nil, fmt.Errorf("GetRepositoryById: %v", err)
  205. }
  206. ctx.Data["repo_name"] = forkRepo.Name
  207. ctx.Data["desc"] = forkRepo.Description
  208. if err = forkRepo.GetOwner(); err != nil {
  209. return nil, fmt.Errorf("GetOwner: %v", err)
  210. }
  211. ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name
  212. return forkRepo, nil
  213. }
  214. func Fork(ctx *middleware.Context) {
  215. ctx.Data["Title"] = ctx.Tr("new_fork")
  216. if _, err := getForkRepository(ctx); err != nil {
  217. if models.IsErrRepoNotExist(err) {
  218. ctx.Redirect(setting.AppSubUrl + "/")
  219. } else {
  220. ctx.Handle(500, "getForkRepository", err)
  221. }
  222. return
  223. }
  224. // FIXME: maybe sometime can directly fork to organization?
  225. ctx.Data["ContextUser"] = ctx.User
  226. if err := ctx.User.GetOrganizations(); err != nil {
  227. ctx.Handle(500, "GetOrganizations", err)
  228. return
  229. }
  230. ctx.Data["Orgs"] = ctx.User.Orgs
  231. ctx.HTML(200, FORK)
  232. }
  233. func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
  234. ctx.Data["Title"] = ctx.Tr("new_fork")
  235. forkRepo, err := getForkRepository(ctx)
  236. if err != nil {
  237. if models.IsErrRepoNotExist(err) {
  238. ctx.Redirect(setting.AppSubUrl + "/")
  239. } else {
  240. ctx.Handle(500, "getForkRepository", err)
  241. }
  242. return
  243. }
  244. ctxUser := ctx.User
  245. // Not equal means current user is an organization.
  246. if form.Uid != ctx.User.Id {
  247. var err error
  248. ctxUser, err = checkContextUser(ctx, form.Uid)
  249. if err != nil {
  250. ctx.Handle(500, "checkContextUser", err)
  251. return
  252. }
  253. }
  254. ctx.Data["ContextUser"] = ctxUser
  255. if err := ctx.User.GetOrganizations(); err != nil {
  256. ctx.Handle(500, "GetOrganizations", err)
  257. return
  258. }
  259. ctx.Data["Orgs"] = ctx.User.Orgs
  260. if ctx.HasError() {
  261. ctx.HTML(200, CREATE)
  262. return
  263. }
  264. if ctxUser.IsOrganization() {
  265. // Check ownership of organization.
  266. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  267. ctx.Error(403)
  268. return
  269. }
  270. }
  271. repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description)
  272. if err == nil {
  273. log.Trace("Repository forked: %s/%s", ctxUser.Name, repo.Name)
  274. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  275. return
  276. } else if err == models.ErrRepoAlreadyExist {
  277. ctx.Data["Err_RepoName"] = true
  278. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), FORK, &form)
  279. return
  280. } else if err == models.ErrRepoNameIllegal {
  281. ctx.Data["Err_RepoName"] = true
  282. ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), CREATE, &form)
  283. return
  284. }
  285. if repo != nil {
  286. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  287. log.Error(4, "DeleteRepository: %v", errDelete)
  288. }
  289. }
  290. ctx.Handle(500, "ForkPost", err)
  291. }
  292. func Action(ctx *middleware.Context) {
  293. var err error
  294. switch ctx.Params(":action") {
  295. case "watch":
  296. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  297. case "unwatch":
  298. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  299. case "star":
  300. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  301. case "unstar":
  302. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  303. case "desc":
  304. if !ctx.Repo.IsOwner() {
  305. ctx.Error(404)
  306. return
  307. }
  308. ctx.Repo.Repository.Description = ctx.Query("desc")
  309. ctx.Repo.Repository.Website = ctx.Query("site")
  310. err = models.UpdateRepository(ctx.Repo.Repository, false)
  311. }
  312. if err != nil {
  313. log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
  314. ctx.JSON(200, map[string]interface{}{
  315. "ok": false,
  316. "err": err.Error(),
  317. })
  318. return
  319. }
  320. ctx.Redirect(ctx.Repo.RepoLink)
  321. return
  322. ctx.JSON(200, map[string]interface{}{
  323. "ok": true,
  324. })
  325. }
  326. func Download(ctx *middleware.Context) {
  327. var (
  328. uri = ctx.Params("*")
  329. refName string
  330. ext string
  331. archivePath string
  332. archiveType git.ArchiveType
  333. )
  334. switch {
  335. case strings.HasSuffix(uri, ".zip"):
  336. ext = ".zip"
  337. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  338. archiveType = git.ZIP
  339. case strings.HasSuffix(uri, ".tar.gz"):
  340. ext = ".tar.gz"
  341. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  342. archiveType = git.TARGZ
  343. default:
  344. ctx.Error(404)
  345. return
  346. }
  347. refName = strings.TrimSuffix(uri, ext)
  348. if !com.IsDir(archivePath) {
  349. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  350. ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err)
  351. return
  352. }
  353. }
  354. // Get corresponding commit.
  355. var (
  356. commit *git.Commit
  357. err error
  358. )
  359. gitRepo := ctx.Repo.GitRepo
  360. if gitRepo.IsBranchExist(refName) {
  361. commit, err = gitRepo.GetCommitOfBranch(refName)
  362. if err != nil {
  363. ctx.Handle(500, "Download", err)
  364. return
  365. }
  366. } else if gitRepo.IsTagExist(refName) {
  367. commit, err = gitRepo.GetCommitOfTag(refName)
  368. if err != nil {
  369. ctx.Handle(500, "Download", err)
  370. return
  371. }
  372. } else if len(refName) == 40 {
  373. commit, err = gitRepo.GetCommit(refName)
  374. if err != nil {
  375. ctx.Handle(404, "Download", nil)
  376. return
  377. }
  378. } else {
  379. ctx.Error(404)
  380. return
  381. }
  382. archivePath = path.Join(archivePath, base.ShortSha(commit.Id.String())+ext)
  383. if !com.IsFile(archivePath) {
  384. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  385. ctx.Handle(500, "Download -> CreateArchive "+archivePath, err)
  386. return
  387. }
  388. }
  389. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(commit.Id.String())+ext)
  390. }