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