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

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
Better logging (#6038) (#6095) * Panic don't fatal on create new logger Fixes #5854 Signed-off-by: Andrew Thornton <art27@cantab.net> * partial broken * Update the logging infrastrcture Signed-off-by: Andrew Thornton <art27@cantab.net> * Reset the skip levels for Fatal and Error Signed-off-by: Andrew Thornton <art27@cantab.net> * broken ncsa * More log.Error fixes Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove nal * set log-levels to lowercase * Make console_test test all levels * switch to lowercased levels * OK now working * Fix vetting issues * Fix lint * Fix tests * change default logging to match current gitea * Improve log testing Signed-off-by: Andrew Thornton <art27@cantab.net> * reset error skip levels to 0 * Update documentation and access logger configuration * Redirect the router log back to gitea if redirect macaron log but also allow setting the log level - i.e. TRACE * Fix broken level caching * Refactor the router log * Add Router logger * Add colorizing options * Adjust router colors * Only create logger if they will be used * update app.ini.sample * rename Attribute ColorAttribute * Change from white to green for function * Set fatal/error levels * Restore initial trace logger * Fix Trace arguments in modules/auth/auth.go * Properly handle XORMLogger * Improve admin/config page * fix fmt * Add auto-compression of old logs * Update error log levels * Remove the unnecessary skip argument from Error, Fatal and Critical * Add stacktrace support * Fix tests * Remove x/sync from vendors? * Add stderr option to console logger * Use filepath.ToSlash to protect against Windows in tests * Remove prefixed underscores from names in colors.go * Remove not implemented database logger This was removed from Gogs on 4 Mar 2016 but left in the configuration since then. * Ensure that log paths are relative to ROOT_PATH * use path.Join * rename jsonConfig to logConfig * Rename "config" to "jsonConfig" to make it clearer * Requested changes * Requested changes: XormLogger * Try to color the windows terminal If successful default to colorizing the console logs * fixup * Colorize initially too * update vendor * Colorize logs on default and remove if this is not a colorizing logger * Fix documentation * fix test * Use go-isatty to detect if on windows we are on msys or cygwin * Fix spelling mistake * Add missing vendors * More changes * Rationalise the ANSI writer protection * Adjust colors on advice from @0x5c * Make Flags a comma separated list * Move to use the windows constant for ENABLE_VIRTUAL_TERMINAL_PROCESSING * Ensure matching is done on the non-colored message - to simpify EXPRESSION
6 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/auth"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/git"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/migrations"
  17. "code.gitea.io/gitea/modules/notification"
  18. "code.gitea.io/gitea/modules/setting"
  19. "code.gitea.io/gitea/modules/util"
  20. "github.com/unknwon/com"
  21. )
  22. const (
  23. tplCreate base.TplName = "repo/create"
  24. tplMigrate base.TplName = "repo/migrate"
  25. )
  26. // MustBeNotEmpty render when a repo is a empty git dir
  27. func MustBeNotEmpty(ctx *context.Context) {
  28. if ctx.Repo.Repository.IsEmpty {
  29. ctx.NotFound("MustBeNotEmpty", nil)
  30. }
  31. }
  32. // MustBeEditable check that repo can be edited
  33. func MustBeEditable(ctx *context.Context) {
  34. if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
  35. ctx.NotFound("", nil)
  36. return
  37. }
  38. }
  39. // MustBeAbleToUpload check that repo can be uploaded to
  40. func MustBeAbleToUpload(ctx *context.Context) {
  41. if !setting.Repository.Upload.Enabled {
  42. ctx.NotFound("", nil)
  43. }
  44. }
  45. func checkContextUser(ctx *context.Context, uid int64) *models.User {
  46. orgs, err := models.GetOwnedOrgsByUserIDDesc(ctx.User.ID, "updated_unix")
  47. if err != nil {
  48. ctx.ServerError("GetOwnedOrgsByUserIDDesc", err)
  49. return nil
  50. }
  51. ctx.Data["Orgs"] = orgs
  52. // Not equal means current user is an organization.
  53. if uid == ctx.User.ID || uid == 0 {
  54. return ctx.User
  55. }
  56. org, err := models.GetUserByID(uid)
  57. if models.IsErrUserNotExist(err) {
  58. return ctx.User
  59. }
  60. if err != nil {
  61. ctx.ServerError("GetUserByID", fmt.Errorf("[%d]: %v", uid, err))
  62. return nil
  63. }
  64. // Check ownership of organization.
  65. if !org.IsOrganization() {
  66. ctx.Error(403)
  67. return nil
  68. }
  69. if !ctx.User.IsAdmin {
  70. isOwner, err := org.IsOwnedBy(ctx.User.ID)
  71. if err != nil {
  72. ctx.ServerError("IsOwnedBy", err)
  73. return nil
  74. } else if !isOwner {
  75. ctx.Error(403)
  76. return nil
  77. }
  78. }
  79. return org
  80. }
  81. func getRepoPrivate(ctx *context.Context) bool {
  82. switch strings.ToLower(setting.Repository.DefaultPrivate) {
  83. case setting.RepoCreatingLastUserVisibility:
  84. return ctx.User.LastRepoVisibility
  85. case setting.RepoCreatingPrivate:
  86. return true
  87. case setting.RepoCreatingPublic:
  88. return false
  89. default:
  90. return ctx.User.LastRepoVisibility
  91. }
  92. }
  93. // Create render creating repository page
  94. func Create(ctx *context.Context) {
  95. if !ctx.User.CanCreateRepo() {
  96. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", ctx.User.MaxCreationLimit()), tplCreate, nil)
  97. }
  98. ctx.Data["Title"] = ctx.Tr("new_repo")
  99. // Give default value for template to render.
  100. ctx.Data["Gitignores"] = models.Gitignores
  101. ctx.Data["LabelTemplates"] = models.LabelTemplates
  102. ctx.Data["Licenses"] = models.Licenses
  103. ctx.Data["Readmes"] = models.Readmes
  104. ctx.Data["readme"] = "Default"
  105. ctx.Data["private"] = getRepoPrivate(ctx)
  106. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  107. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  108. if ctx.Written() {
  109. return
  110. }
  111. ctx.Data["ContextUser"] = ctxUser
  112. ctx.HTML(200, tplCreate)
  113. }
  114. func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) {
  115. switch {
  116. case migrations.IsRateLimitError(err):
  117. ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
  118. case models.IsErrReachLimitOfRepo(err):
  119. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
  120. case models.IsErrRepoAlreadyExist(err):
  121. ctx.Data["Err_RepoName"] = true
  122. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
  123. case models.IsErrNameReserved(err):
  124. ctx.Data["Err_RepoName"] = true
  125. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
  126. case models.IsErrNamePatternNotAllowed(err):
  127. ctx.Data["Err_RepoName"] = true
  128. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
  129. default:
  130. ctx.ServerError(name, err)
  131. }
  132. }
  133. // CreatePost response for creating repository
  134. func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
  135. ctx.Data["Title"] = ctx.Tr("new_repo")
  136. ctx.Data["Gitignores"] = models.Gitignores
  137. ctx.Data["LabelTemplates"] = models.LabelTemplates
  138. ctx.Data["Licenses"] = models.Licenses
  139. ctx.Data["Readmes"] = models.Readmes
  140. ctxUser := checkContextUser(ctx, form.UID)
  141. if ctx.Written() {
  142. return
  143. }
  144. ctx.Data["ContextUser"] = ctxUser
  145. if ctx.HasError() {
  146. ctx.HTML(200, tplCreate)
  147. return
  148. }
  149. repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
  150. Name: form.RepoName,
  151. Description: form.Description,
  152. Gitignores: form.Gitignores,
  153. IssueLabels: form.IssueLabels,
  154. License: form.License,
  155. Readme: form.Readme,
  156. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  157. AutoInit: form.AutoInit,
  158. })
  159. if err == nil {
  160. notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
  161. log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
  162. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
  163. return
  164. }
  165. if repo != nil {
  166. if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
  167. log.Error("DeleteRepository: %v", errDelete)
  168. }
  169. }
  170. handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
  171. }
  172. // Migrate render migration of repository page
  173. func Migrate(ctx *context.Context) {
  174. ctx.Data["Title"] = ctx.Tr("new_migrate")
  175. ctx.Data["private"] = getRepoPrivate(ctx)
  176. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  177. ctx.Data["mirror"] = ctx.Query("mirror") == "1"
  178. ctx.Data["wiki"] = ctx.Query("wiki") == "1"
  179. ctx.Data["milestones"] = ctx.Query("milestones") == "1"
  180. ctx.Data["labels"] = ctx.Query("labels") == "1"
  181. ctx.Data["issues"] = ctx.Query("issues") == "1"
  182. ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1"
  183. ctx.Data["releases"] = ctx.Query("releases") == "1"
  184. ctx.Data["LFSActive"] = setting.LFS.StartServer
  185. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  186. if ctx.Written() {
  187. return
  188. }
  189. ctx.Data["ContextUser"] = ctxUser
  190. ctx.HTML(200, tplMigrate)
  191. }
  192. // MigratePost response for migrating from external git repository
  193. func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
  194. ctx.Data["Title"] = ctx.Tr("new_migrate")
  195. ctxUser := checkContextUser(ctx, form.UID)
  196. if ctx.Written() {
  197. return
  198. }
  199. ctx.Data["ContextUser"] = ctxUser
  200. if ctx.HasError() {
  201. ctx.HTML(200, tplMigrate)
  202. return
  203. }
  204. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  205. if err != nil {
  206. if models.IsErrInvalidCloneAddr(err) {
  207. ctx.Data["Err_CloneAddr"] = true
  208. addrErr := err.(models.ErrInvalidCloneAddr)
  209. switch {
  210. case addrErr.IsURLError:
  211. ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form)
  212. case addrErr.IsPermissionDenied:
  213. ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form)
  214. case addrErr.IsInvalidPath:
  215. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form)
  216. default:
  217. ctx.ServerError("Unknown error", err)
  218. }
  219. } else {
  220. ctx.ServerError("ParseRemoteAddr", err)
  221. }
  222. return
  223. }
  224. var opts = migrations.MigrateOptions{
  225. RemoteURL: remoteAddr,
  226. Name: form.RepoName,
  227. Description: form.Description,
  228. Private: form.Private || setting.Repository.ForcePrivate,
  229. Mirror: form.Mirror,
  230. AuthUsername: form.AuthUsername,
  231. AuthPassword: form.AuthPassword,
  232. Wiki: form.Wiki,
  233. Issues: form.Issues,
  234. Milestones: form.Milestones,
  235. Labels: form.Labels,
  236. Comments: true,
  237. PullRequests: form.PullRequests,
  238. Releases: form.Releases,
  239. }
  240. if opts.Mirror {
  241. opts.Issues = false
  242. opts.Milestones = false
  243. opts.Labels = false
  244. opts.Comments = false
  245. opts.PullRequests = false
  246. opts.Releases = false
  247. }
  248. repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
  249. if err == nil {
  250. notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
  251. log.Trace("Repository migrated [%d]: %s/%s successfully", repo.ID, ctxUser.Name, form.RepoName)
  252. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName)
  253. return
  254. }
  255. switch {
  256. case models.IsErrReachLimitOfRepo(err):
  257. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", ctxUser.MaxCreationLimit()), tplMigrate, &form)
  258. case models.IsErrNameReserved(err):
  259. ctx.Data["Err_RepoName"] = true
  260. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplMigrate, &form)
  261. case models.IsErrRepoAlreadyExist(err):
  262. ctx.Data["Err_RepoName"] = true
  263. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplMigrate, &form)
  264. case models.IsErrNamePatternNotAllowed(err):
  265. ctx.Data["Err_RepoName"] = true
  266. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplMigrate, &form)
  267. case migrations.IsRateLimitError(err):
  268. ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tplMigrate, &form)
  269. case migrations.IsTwoFactorAuthError(err):
  270. ctx.Data["Err_Auth"] = true
  271. ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tplMigrate, &form)
  272. default:
  273. // remoteAddr may contain credentials, so we sanitize it
  274. err = util.URLSanitizedError(err, remoteAddr)
  275. if strings.Contains(err.Error(), "Authentication failed") ||
  276. strings.Contains(err.Error(), "Bad credentials") ||
  277. strings.Contains(err.Error(), "could not read Username") {
  278. ctx.Data["Err_Auth"] = true
  279. ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tplMigrate, &form)
  280. } else if strings.Contains(err.Error(), "fatal:") {
  281. ctx.Data["Err_CloneAddr"] = true
  282. ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tplMigrate, &form)
  283. } else {
  284. ctx.ServerError("MigratePost", err)
  285. }
  286. }
  287. }
  288. // Action response for actions to a repository
  289. func Action(ctx *context.Context) {
  290. var err error
  291. switch ctx.Params(":action") {
  292. case "watch":
  293. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  294. case "unwatch":
  295. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  296. case "star":
  297. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  298. case "unstar":
  299. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  300. case "desc": // FIXME: this is not used
  301. if !ctx.Repo.IsOwner() {
  302. ctx.Error(404)
  303. return
  304. }
  305. ctx.Repo.Repository.Description = ctx.Query("desc")
  306. ctx.Repo.Repository.Website = ctx.Query("site")
  307. err = models.UpdateRepository(ctx.Repo.Repository, false)
  308. }
  309. if err != nil {
  310. ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  311. return
  312. }
  313. ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink)
  314. }
  315. // RedirectDownload return a file based on the following infos:
  316. func RedirectDownload(ctx *context.Context) {
  317. var (
  318. vTag = ctx.Params("vTag")
  319. fileName = ctx.Params("fileName")
  320. )
  321. tagNames := []string{vTag}
  322. curRepo := ctx.Repo.Repository
  323. releases, err := models.GetReleasesByRepoIDAndNames(curRepo.ID, tagNames)
  324. if err != nil {
  325. if models.IsErrAttachmentNotExist(err) {
  326. ctx.Error(404)
  327. return
  328. }
  329. ctx.ServerError("RedirectDownload", err)
  330. return
  331. }
  332. if len(releases) == 1 {
  333. release := releases[0]
  334. att, err := models.GetAttachmentByReleaseIDFileName(release.ID, fileName)
  335. if err != nil {
  336. ctx.Error(404)
  337. return
  338. }
  339. if att != nil {
  340. ctx.Redirect(setting.AppSubURL + "/attachments/" + att.UUID)
  341. return
  342. }
  343. }
  344. ctx.Error(404)
  345. }
  346. // Download download an archive of a repository
  347. func Download(ctx *context.Context) {
  348. var (
  349. uri = ctx.Params("*")
  350. refName string
  351. ext string
  352. archivePath string
  353. archiveType git.ArchiveType
  354. )
  355. switch {
  356. case strings.HasSuffix(uri, ".zip"):
  357. ext = ".zip"
  358. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  359. archiveType = git.ZIP
  360. case strings.HasSuffix(uri, ".tar.gz"):
  361. ext = ".tar.gz"
  362. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  363. archiveType = git.TARGZ
  364. default:
  365. log.Trace("Unknown format: %s", uri)
  366. ctx.Error(404)
  367. return
  368. }
  369. refName = strings.TrimSuffix(uri, ext)
  370. if !com.IsDir(archivePath) {
  371. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  372. ctx.ServerError("Download -> os.MkdirAll(archivePath)", err)
  373. return
  374. }
  375. }
  376. // Get corresponding commit.
  377. var (
  378. commit *git.Commit
  379. err error
  380. )
  381. gitRepo := ctx.Repo.GitRepo
  382. if gitRepo.IsBranchExist(refName) {
  383. commit, err = gitRepo.GetBranchCommit(refName)
  384. if err != nil {
  385. ctx.ServerError("GetBranchCommit", err)
  386. return
  387. }
  388. } else if gitRepo.IsTagExist(refName) {
  389. commit, err = gitRepo.GetTagCommit(refName)
  390. if err != nil {
  391. ctx.ServerError("GetTagCommit", err)
  392. return
  393. }
  394. } else if len(refName) >= 4 && len(refName) <= 40 {
  395. commit, err = gitRepo.GetCommit(refName)
  396. if err != nil {
  397. ctx.NotFound("GetCommit", nil)
  398. return
  399. }
  400. } else {
  401. ctx.NotFound("Download", nil)
  402. return
  403. }
  404. archivePath = path.Join(archivePath, base.ShortSha(commit.ID.String())+ext)
  405. if !com.IsFile(archivePath) {
  406. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  407. ctx.ServerError("Download -> CreateArchive "+archivePath, err)
  408. return
  409. }
  410. }
  411. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext)
  412. }