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
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
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
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
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
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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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. "encoding/base64"
  7. "errors"
  8. "fmt"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "github.com/go-martini/martini"
  13. "github.com/gogits/gogs/models"
  14. "github.com/gogits/gogs/modules/auth"
  15. "github.com/gogits/gogs/modules/base"
  16. "github.com/gogits/gogs/modules/log"
  17. "github.com/gogits/gogs/modules/middleware"
  18. )
  19. func Create(ctx *middleware.Context) {
  20. ctx.Data["Title"] = "Create repository"
  21. ctx.Data["PageIsNewRepo"] = true
  22. ctx.Data["LanguageIgns"] = models.LanguageIgns
  23. ctx.Data["Licenses"] = models.Licenses
  24. ctx.HTML(200, "repo/create")
  25. }
  26. func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
  27. ctx.Data["Title"] = "Create repository"
  28. ctx.Data["PageIsNewRepo"] = true
  29. ctx.Data["LanguageIgns"] = models.LanguageIgns
  30. ctx.Data["Licenses"] = models.Licenses
  31. if ctx.HasError() {
  32. ctx.HTML(200, "repo/create")
  33. return
  34. }
  35. _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
  36. form.Language, form.License, form.Private == "on", form.InitReadme == "on")
  37. if err == nil {
  38. log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
  39. ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
  40. return
  41. } else if err == models.ErrRepoAlreadyExist {
  42. ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
  43. return
  44. } else if err == models.ErrRepoNameIllegal {
  45. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form)
  46. return
  47. }
  48. ctx.Handle(500, "repo.Create", err)
  49. }
  50. func Mirror(ctx *middleware.Context) {
  51. ctx.Data["Title"] = "Mirror repository"
  52. ctx.Data["PageIsNewRepo"] = true
  53. ctx.HTML(200, "repo/mirror")
  54. }
  55. func MirrorPost(ctx *middleware.Context, form auth.CreateRepoForm) {
  56. ctx.Data["Title"] = "Mirror repository"
  57. ctx.Data["PageIsNewRepo"] = true
  58. if ctx.HasError() {
  59. ctx.HTML(200, "repo/mirror")
  60. return
  61. }
  62. _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
  63. "", form.License, form.Private == "on", false)
  64. if err == nil {
  65. log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
  66. ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
  67. return
  68. } else if err == models.ErrRepoAlreadyExist {
  69. ctx.RenderWithErr("Repository name has already been used", "repo/mirror", &form)
  70. return
  71. } else if err == models.ErrRepoNameIllegal {
  72. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/mirror", &form)
  73. return
  74. }
  75. ctx.Handle(500, "repo.Mirror", err)
  76. }
  77. func Single(ctx *middleware.Context, params martini.Params) {
  78. branchName := ctx.Repo.BranchName
  79. commitId := ctx.Repo.CommitId
  80. userName := ctx.Repo.Owner.Name
  81. repoName := ctx.Repo.Repository.Name
  82. repoLink := ctx.Repo.RepoLink
  83. branchLink := ctx.Repo.RepoLink + "/src/" + branchName
  84. rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
  85. // Get tree path
  86. treename := params["_1"]
  87. if len(treename) > 0 && treename[len(treename)-1] == '/' {
  88. ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
  89. return
  90. }
  91. ctx.Data["IsRepoToolbarSource"] = true
  92. // Branches.
  93. brs, err := models.GetBranches(userName, repoName)
  94. if err != nil {
  95. ctx.Handle(404, "repo.Single(GetBranches)", err)
  96. return
  97. }
  98. ctx.Data["Branches"] = brs
  99. isViewBranch := ctx.Repo.IsBranch
  100. ctx.Data["IsViewBranch"] = isViewBranch
  101. repoFile, err := models.GetTargetFile(userName, repoName,
  102. branchName, commitId, treename)
  103. if err != nil && err != models.ErrRepoFileNotExist {
  104. ctx.Handle(404, "repo.Single(GetTargetFile)", err)
  105. return
  106. }
  107. if len(treename) != 0 && repoFile == nil {
  108. ctx.Handle(404, "repo.Single", nil)
  109. return
  110. }
  111. if repoFile != nil && repoFile.IsFile() {
  112. if blob, err := repoFile.LookupBlob(); err != nil {
  113. ctx.Handle(404, "repo.Single(repoFile.LookupBlob)", err)
  114. } else {
  115. ctx.Data["FileSize"] = repoFile.Size
  116. ctx.Data["IsFile"] = true
  117. ctx.Data["FileName"] = repoFile.Name
  118. ext := path.Ext(repoFile.Name)
  119. if len(ext) > 0 {
  120. ext = ext[1:]
  121. }
  122. ctx.Data["FileExt"] = ext
  123. ctx.Data["FileLink"] = rawLink + "/" + treename
  124. data := blob.Contents()
  125. _, isTextFile := base.IsTextFile(data)
  126. _, isImageFile := base.IsImageFile(data)
  127. ctx.Data["FileIsText"] = isTextFile
  128. if isImageFile {
  129. ctx.Data["IsImageFile"] = true
  130. } else {
  131. readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
  132. ctx.Data["ReadmeExist"] = readmeExist
  133. if readmeExist {
  134. ctx.Data["FileContent"] = string(base.RenderMarkdown(data, ""))
  135. } else {
  136. if isTextFile {
  137. ctx.Data["FileContent"] = string(data)
  138. }
  139. }
  140. }
  141. }
  142. } else {
  143. // Directory and file list.
  144. files, err := models.GetReposFiles(userName, repoName, ctx.Repo.CommitId, treename)
  145. if err != nil {
  146. ctx.Handle(404, "repo.Single(GetReposFiles)", err)
  147. return
  148. }
  149. ctx.Data["Files"] = files
  150. var readmeFile *models.RepoFile
  151. for _, f := range files {
  152. if !f.IsFile() || !base.IsReadmeFile(f.Name) {
  153. continue
  154. } else {
  155. readmeFile = f
  156. break
  157. }
  158. }
  159. if readmeFile != nil {
  160. ctx.Data["ReadmeInSingle"] = true
  161. ctx.Data["ReadmeExist"] = true
  162. if blob, err := readmeFile.LookupBlob(); err != nil {
  163. ctx.Handle(404, "repo.Single(readmeFile.LookupBlob)", err)
  164. return
  165. } else {
  166. ctx.Data["FileSize"] = readmeFile.Size
  167. ctx.Data["FileLink"] = rawLink + "/" + treename
  168. data := blob.Contents()
  169. _, isTextFile := base.IsTextFile(data)
  170. ctx.Data["FileIsText"] = isTextFile
  171. ctx.Data["FileName"] = readmeFile.Name
  172. if isTextFile {
  173. ctx.Data["FileContent"] = string(base.RenderMarkdown(data, branchLink))
  174. }
  175. }
  176. }
  177. }
  178. ctx.Data["Username"] = userName
  179. ctx.Data["Reponame"] = repoName
  180. var treenames []string
  181. Paths := make([]string, 0)
  182. if len(treename) > 0 {
  183. treenames = strings.Split(treename, "/")
  184. for i, _ := range treenames {
  185. Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
  186. }
  187. ctx.Data["HasParentPath"] = true
  188. if len(Paths)-2 >= 0 {
  189. ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
  190. }
  191. }
  192. ctx.Data["LastCommit"] = ctx.Repo.Commit
  193. ctx.Data["Paths"] = Paths
  194. ctx.Data["Treenames"] = treenames
  195. ctx.Data["BranchLink"] = branchLink
  196. ctx.HTML(200, "repo/single")
  197. }
  198. func SingleDownload(ctx *middleware.Context, params martini.Params) {
  199. // Get tree path
  200. treename := params["_1"]
  201. branchName := params["branchname"]
  202. userName := params["username"]
  203. repoName := params["reponame"]
  204. var commitId string
  205. if !models.IsBranchExist(userName, repoName, branchName) {
  206. commitId = branchName
  207. branchName = ""
  208. }
  209. repoFile, err := models.GetTargetFile(userName, repoName,
  210. branchName, commitId, treename)
  211. if err != nil {
  212. ctx.Handle(404, "repo.SingleDownload(GetTargetFile)", err)
  213. return
  214. }
  215. blob, err := repoFile.LookupBlob()
  216. if err != nil {
  217. ctx.Handle(404, "repo.SingleDownload(LookupBlob)", err)
  218. return
  219. }
  220. data := blob.Contents()
  221. contentType, isTextFile := base.IsTextFile(data)
  222. _, isImageFile := base.IsImageFile(data)
  223. ctx.Res.Header().Set("Content-Type", contentType)
  224. if !isTextFile && !isImageFile {
  225. ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename))
  226. ctx.Res.Header().Set("Content-Transfer-Encoding", "binary")
  227. }
  228. ctx.Res.Write(data)
  229. }
  230. func basicEncode(username, password string) string {
  231. auth := username + ":" + password
  232. return base64.StdEncoding.EncodeToString([]byte(auth))
  233. }
  234. func basicDecode(encoded string) (user string, name string, err error) {
  235. var s []byte
  236. s, err = base64.StdEncoding.DecodeString(encoded)
  237. if err != nil {
  238. return
  239. }
  240. a := strings.Split(string(s), ":")
  241. if len(a) == 2 {
  242. user, name = a[0], a[1]
  243. } else {
  244. err = errors.New("decode failed")
  245. }
  246. return
  247. }
  248. func authRequired(ctx *middleware.Context) {
  249. ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
  250. ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
  251. ctx.HTML(401, fmt.Sprintf("status/401"))
  252. }
  253. func Setting(ctx *middleware.Context, params martini.Params) {
  254. if !ctx.Repo.IsOwner {
  255. ctx.Handle(404, "repo.Setting", nil)
  256. return
  257. }
  258. ctx.Data["IsRepoToolbarSetting"] = true
  259. var title string
  260. if t, ok := ctx.Data["Title"].(string); ok {
  261. title = t
  262. }
  263. ctx.Data["Title"] = title + " - settings"
  264. ctx.HTML(200, "repo/setting")
  265. }
  266. func SettingPost(ctx *middleware.Context) {
  267. if !ctx.Repo.IsOwner {
  268. ctx.Error(404)
  269. return
  270. }
  271. switch ctx.Query("action") {
  272. case "update":
  273. newRepoName := ctx.Query("name")
  274. // Check if repository name has been changed.
  275. if ctx.Repo.Repository.Name != newRepoName {
  276. isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName)
  277. if err != nil {
  278. ctx.Handle(500, "repo.SettingPost(update: check existence)", err)
  279. return
  280. } else if isExist {
  281. ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil)
  282. return
  283. } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
  284. ctx.Handle(500, "repo.SettingPost(change repository name)", err)
  285. return
  286. }
  287. log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName)
  288. ctx.Repo.Repository.Name = newRepoName
  289. }
  290. br := ctx.Query("branch")
  291. if models.IsBranchExist(ctx.User.Name, ctx.Repo.Repository.Name, br) {
  292. ctx.Repo.Repository.DefaultBranch = br
  293. }
  294. ctx.Repo.Repository.Description = ctx.Query("desc")
  295. ctx.Repo.Repository.Website = ctx.Query("site")
  296. ctx.Repo.Repository.IsGoget = ctx.Query("goget") == "on"
  297. if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
  298. ctx.Handle(404, "repo.SettingPost(update)", err)
  299. return
  300. }
  301. log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  302. ctx.Flash.Success("Repository options has been successfully updated.")
  303. ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
  304. case "transfer":
  305. if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
  306. ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
  307. return
  308. }
  309. newOwner := ctx.Query("owner")
  310. // Check if new owner exists.
  311. isExist, err := models.IsUserExist(newOwner)
  312. if err != nil {
  313. ctx.Handle(500, "repo.SettingPost(transfer: check existence)", err)
  314. return
  315. } else if !isExist {
  316. ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil)
  317. return
  318. } else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
  319. ctx.Handle(500, "repo.SettingPost(transfer repository)", err)
  320. return
  321. }
  322. log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner)
  323. ctx.Redirect("/")
  324. case "delete":
  325. if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
  326. ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
  327. return
  328. }
  329. if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil {
  330. ctx.Handle(500, "repo.Delete", err)
  331. return
  332. }
  333. log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
  334. ctx.Redirect("/")
  335. }
  336. }
  337. func Action(ctx *middleware.Context, params martini.Params) {
  338. var err error
  339. switch params["action"] {
  340. case "watch":
  341. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  342. case "unwatch":
  343. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  344. case "desc":
  345. if !ctx.Repo.IsOwner {
  346. ctx.Error(404)
  347. return
  348. }
  349. ctx.Repo.Repository.Description = ctx.Query("desc")
  350. ctx.Repo.Repository.Website = ctx.Query("site")
  351. err = models.UpdateRepository(ctx.Repo.Repository)
  352. }
  353. if err != nil {
  354. log.Error("repo.Action(%s): %v", params["action"], err)
  355. ctx.JSON(200, map[string]interface{}{
  356. "ok": false,
  357. "err": err.Error(),
  358. })
  359. return
  360. }
  361. ctx.JSON(200, map[string]interface{}{
  362. "ok": true,
  363. })
  364. }
  365. func Import(ctx *middleware.Context, params martini.Params) {
  366. ctx.ResponseWriter.Write([]byte("not done yet"))
  367. }