Browse Source

Merge branch 'develop' into api/github-compliance

pull/3742/head
Kim "BKC" Carlbäcker 8 years ago committed by GitHub
parent
commit
4e4ed0cb20
  1. 2
      .github/ISSUE_TEMPLATE.md
  2. 1
      .gitignore
  3. 6
      .gopmfile
  4. 24
      .travis.yml
  5. 4
      Makefile
  6. 8
      README.md
  7. 8
      README_ZH.md
  8. 2
      appveyor.yml
  9. 14
      cmd/dump.go
  10. 140
      cmd/hook.go
  11. 196
      cmd/serv.go
  12. 58
      cmd/update.go
  13. 31
      cmd/web.go
  14. 127
      conf/app.ini
  15. 4
      conf/locale/locale_bg-BG.ini
  16. 4
      conf/locale/locale_cs-CZ.ini
  17. 12
      conf/locale/locale_de-DE.ini
  18. 7
      conf/locale/locale_en-US.ini
  19. 22
      conf/locale/locale_es-ES.ini
  20. 4
      conf/locale/locale_fi-FI.ini
  21. 4
      conf/locale/locale_fr-FR.ini
  22. 4
      conf/locale/locale_gl-ES.ini
  23. 4
      conf/locale/locale_it-IT.ini
  24. 4
      conf/locale/locale_ja-JP.ini
  25. 4
      conf/locale/locale_ko-KR.ini
  26. 4
      conf/locale/locale_lv-LV.ini
  27. 4
      conf/locale/locale_nl-NL.ini
  28. 4
      conf/locale/locale_pl-PL.ini
  29. 4
      conf/locale/locale_pt-BR.ini
  30. 26
      conf/locale/locale_ru-RU.ini
  31. 4
      conf/locale/locale_sr-SP.ini
  32. 4
      conf/locale/locale_sv-SE.ini
  33. 4
      conf/locale/locale_tr-TR.ini
  34. 4
      conf/locale/locale_zh-CN.ini
  35. 4
      conf/locale/locale_zh-HK.ini
  36. 28
      conf/locale/locale_zh-TW.ini
  37. 14
      docker/build.sh
  38. 154
      glide.lock
  39. 59
      glide.yaml
  40. 6
      gogs.go
  41. 2
      models/access.go
  42. 4
      models/action.go
  43. 2
      models/admin.go
  44. 175
      models/attachment.go
  45. 2
      models/comment.go
  46. 2
      models/git_diff.go
  47. 530
      models/issue.go
  48. 2
      models/issue_mail.go
  49. 2
      models/login_source.go
  50. 5
      models/migrations/migrations.go
  51. 91
      models/migrations/v15.go
  52. 349
      models/milestone.go
  53. 2
      models/mirror.go
  54. 36
      models/models.go
  55. 18
      models/models_tidb.go
  56. 2
      models/org.go
  57. 25
      models/org_team.go
  58. 18
      models/pull.go
  59. 80
      models/repo.go
  60. 23
      models/repo_collaboration.go
  61. 2
      models/repo_editor.go
  62. 16
      models/ssh_key.go
  63. 6
      models/update.go
  64. 10
      models/user.go
  65. 6
      models/webhook.go
  66. 32
      models/webhook_slack.go
  67. 4
      models/wiki.go
  68. 2
      modules/auth/auth.go
  69. 43
      modules/auth/ldap/ldap.go
  70. 2
      modules/auth/user_form.go
  71. 13
      modules/base/tool.go
  72. 92
      modules/bindata/bindata.go
  73. 2
      modules/context/api.go
  74. 27
      modules/context/context.go
  75. 20
      modules/context/repo.go
  76. 3
      modules/cron/cron.go
  77. 104
      modules/log/conn.go
  78. 73
      modules/log/console.go
  79. 243
      modules/log/file.go
  80. 312
      modules/log/log.go
  81. 87
      modules/log/smtp.go
  82. 2
      modules/mailer/mail.go
  83. 2
      modules/mailer/mailer.go
  84. 2
      modules/markdown/markdown.go
  85. 2
      modules/process/manager.go
  86. 198
      modules/setting/setting.go
  87. 9
      modules/ssh/ssh.go
  88. 2
      modules/template/template.go
  89. 76
      public/assets/librejs/librejs.html
  90. 88
      public/css/gogs.css
  91. BIN
      public/img/avatar_default.png
  92. BIN
      public/img/favicon.png
  93. BIN
      public/img/gogs-large-resize.png
  94. BIN
      public/img/gogs-lg.png
  95. 192
      public/img/gogs.svg
  96. 23
      public/js/gogs.js
  97. 1
      public/less/_home.less
  98. 105
      public/less/_repository.less
  99. 6
      public/plugins/marked-0.3.6/marked.min.js
  100. 1
      public/plugins/notebookjs-0.2.6/notebook.min.js
  101. Some files were not shown because too many files have changed in this diff Show More

2
.github/ISSUE_TEMPLATE.md

@ -18,7 +18,7 @@ The issue will be closed without any reasons if it does not satisfy any of follo
- [ ] Yes (provide example URL) - [ ] Yes (provide example URL)
- [ ] No - [ ] No
- [ ] Not relevant - [ ] Not relevant
- Log gist: - Log gist (usually found in `log/gogs.log`):
## Description ## Description

1
.gitignore vendored

@ -17,4 +17,3 @@ output*
gogs.sublime-project gogs.sublime-project
gogs.sublime-workspace gogs.sublime-workspace
/release /release
vendor

6
.gopmfile

@ -3,7 +3,7 @@ path = github.com/gogits/gogs
[deps] [deps]
github.com/bradfitz/gomemcache = commit:2fafb84 github.com/bradfitz/gomemcache = commit:2fafb84
github.com/urfave/cli = commit:47a988 github.com/urfave/cli = commit:347a988
github.com/go-macaron/binding = commit:4892016 github.com/go-macaron/binding = commit:4892016
github.com/go-macaron/cache = commit:5617353 github.com/go-macaron/cache = commit:5617353
github.com/go-macaron/captcha = commit:8aa5919 github.com/go-macaron/captcha = commit:8aa5919
@ -29,6 +29,8 @@ github.com/klauspost/compress = commit:461e8fd
github.com/klauspost/cpuid = commit:09cded8 github.com/klauspost/cpuid = commit:09cded8
github.com/klauspost/crc32 = commit:cb6bfca github.com/klauspost/crc32 = commit:cb6bfca
github.com/lib/pq = commit:67c3f2a github.com/lib/pq = commit:67c3f2a
github.com/mattn/go-colorable = commit:d228849
github.com/mattn/go-isatty = commit:30a891c
github.com/mattn/go-sqlite3 = commit:ce9149a github.com/mattn/go-sqlite3 = commit:ce9149a
github.com/mcuadros/go-version = commit:257f7b9 github.com/mcuadros/go-version = commit:257f7b9
github.com/microcosm-cc/bluemonday = commit:e797637 github.com/microcosm-cc/bluemonday = commit:e797637
@ -42,6 +44,7 @@ github.com/Unknwon/cae = commit:c6aac99
github.com/Unknwon/com = commit:28b053d github.com/Unknwon/com = commit:28b053d
github.com/Unknwon/i18n = commit:39d6f27 github.com/Unknwon/i18n = commit:39d6f27
github.com/Unknwon/paginater = commit:701c23f github.com/Unknwon/paginater = commit:701c23f
github.com/fatih/color = commit:42c364b
golang.org/x/crypto = commit:dc137be golang.org/x/crypto = commit:dc137be
golang.org/x/net = commit:f249948 golang.org/x/net = commit:f249948
golang.org/x/sys = commit:d75a526 golang.org/x/sys = commit:d75a526
@ -49,6 +52,7 @@ golang.org/x/text = commit:ece019d
gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25 gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
gopkg.in/asn1-ber.v1 = commit:4e86f43 gopkg.in/asn1-ber.v1 = commit:4e86f43
gopkg.in/bufio.v1 = commit:567b2bf gopkg.in/bufio.v1 = commit:567b2bf
gopkg.in/clog.v1 = commit:d359c28
gopkg.in/editorconfig/editorconfig-core-go.v1 = commit:a872f05 gopkg.in/editorconfig/editorconfig-core-go.v1 = commit:a872f05
gopkg.in/gomail.v2 = commit:81ebce5 gopkg.in/gomail.v2 = commit:81ebce5
gopkg.in/ini.v1 = commit:e3c2d47 gopkg.in/ini.v1 = commit:e3c2d47

24
.travis.yml

@ -1,29 +1,17 @@
language: go language: go
go: go:
- 1.5 - 1.5.x
- 1.6 - 1.6.x
- 1.7 - 1.7.x
- master
before_install: before_install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -y libpam-dev - sudo apt-get install -y libpam-dev
- go get github.com/msteinert/pam
install: env:
- go get -t -v ./... - GO15VENDOREXPERIMENT=1
script: script:
- go build -v -tags "pam" - go build -v -tags "pam"
- go test -v -cover -race ./... - go test -v -cover -race ./...
notifications:
email:
- u@gogs.io
slack: gophercn:o5pSanyTeNhnfYc3QnG0X7Wx
webhooks:
urls:
- https://webhooks.gitter.im/e/b590f8e03882f7aedc3e
on_success: change
on_failure: always
on_start: never

4
Makefile

@ -74,3 +74,7 @@ fixme:
todo: todo:
grep -rnw "TODO" routers models modules grep -rnw "TODO" routers models modules
# Legacy code should be remove by the time of release
legacy:
grep -rnw "LEGACY" routers models modules

8
README.md

@ -1,4 +1,4 @@
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) [![Build status](https://ci.appveyor.com/api/projects/status/b9uu5ejl933e2wlt/branch/master?svg=true)](https://ci.appveyor.com/project/Unknwon/gogs/branch/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/gogs/localized.svg)](https://crowdin.com/project/gogs) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Gogs [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) [![Build status](https://ci.appveyor.com/api/projects/status/b9uu5ejl933e2wlt/branch/master?svg=true)](https://ci.appveyor.com/project/Unknwon/gogs/branch/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/gogs/localized.svg)](https://crowdin.com/project/gogs) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
===================== =====================
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true) ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
@ -46,10 +46,11 @@ The goal of this project is to make the easiest, fastest, and most painless way
- Repository issues, pull requests and wiki - Repository issues, pull requests and wiki
- Migrate and mirror repository and its wiki - Migrate and mirror repository and its wiki
- Web editor for repository files and wiki - Web editor for repository files and wiki
- Jupyter Notebook
- Gravatar and Federated avatar with custom source - Gravatar and Federated avatar with custom source
- Mail service - Mail service
- Administration panel - Administration panel
- Supports MySQL, PostgreSQL, SQLite3 and [TiDB](https://github.com/pingcap/tidb) (experimental) - Supports MySQL, PostgreSQL, SQLite3, MSSQL and [TiDB](https://github.com/pingcap/tidb) (experimental)
- Multi-language support ([22 languages](https://crowdin.com/project/gogs)) - Multi-language support ([22 languages](https://crowdin.com/project/gogs))
## System Requirements ## System Requirements
@ -105,6 +106,7 @@ There are 5 ways to install Gogs:
## Software and Service Support ## Software and Service Support
- [Drone](https://github.com/drone/drone) (CI) - [Drone](https://github.com/drone/drone) (CI)
- [Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Gogs+Webhook+Plugin) (CI)
- [Fabric8](http://fabric8.io/) (DevOps) - [Fabric8](http://fabric8.io/) (DevOps)
- [Taiga](https://taiga.io/) (Project Management) - [Taiga](https://taiga.io/) (Project Management)
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT) - [Puppet](https://forge.puppetlabs.com/Siteminds/gogs) (IT)
@ -121,7 +123,7 @@ There are 5 ways to install Gogs:
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron). - Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog). - System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
- Thanks [Rocker](http://weibo.com/rocker1989) for designing Logo. - Thanks [Egon Elbre](https://twitter.com/egonelbre) for designing logo.
- Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan. - Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan.
- Thanks [DigitalOcean](https://www.digitalocean.com) for hosting home and demo sites. - Thanks [DigitalOcean](https://www.digitalocean.com) for hosting home and demo sites.
- Thanks [KeyCDN](https://www.keycdn.com/) and [QiNiu](http://www.qiniu.com/) for providing CDN service. - Thanks [KeyCDN](https://www.keycdn.com/) and [QiNiu](http://www.qiniu.com/) for providing CDN service.

8
README_ZH.md

@ -1,4 +1,4 @@
Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) Gogs [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) [![Build status](https://ci.appveyor.com/api/projects/status/b9uu5ejl933e2wlt/branch/master?svg=true)](https://ci.appveyor.com/project/Unknwon/gogs/branch/master)
===================== =====================
Gogs (Go Git Service) 是一款极易搭建的自助 Git 服务。 Gogs (Go Git Service) 是一款极易搭建的自助 Git 服务。
@ -28,9 +28,10 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 支持迁移和镜像仓库以及它的 Wiki - 支持迁移和镜像仓库以及它的 Wiki
- 支持在线编辑仓库文件和 Wiki - 支持在线编辑仓库文件和 Wiki
- 支持自定义源的 Gravatar 和 Federated Avatar - 支持自定义源的 Gravatar 和 Federated Avatar
- 支持 Jupyter Notebook
- 支持邮件服务 - 支持邮件服务
- 支持后台管理面板 - 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库 - 支持 MySQL、PostgreSQL、SQLite3、MSSQL 和 [TiDB](https://github.com/pingcap/tidb)(实验性支持) 数据库
- 支持多语言本地化([22 种语言]([more](https://crowdin.com/project/gogs))) - 支持多语言本地化([22 种语言]([more](https://crowdin.com/project/gogs)))
## 系统要求 ## 系统要求
@ -74,6 +75,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 软件及服务支持 ## 软件及服务支持
- [Drone](https://github.com/drone/drone)(CI) - [Drone](https://github.com/drone/drone)(CI)
- [Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Gogs+Webhook+Plugin)(CI)
- [Fabric8](http://fabric8.io/)(DevOps) - [Fabric8](http://fabric8.io/)(DevOps)
- [Taiga](https://taiga.io/)(项目管理) - [Taiga](https://taiga.io/)(项目管理)
- [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)(IT) - [Puppet](https://forge.puppetlabs.com/Siteminds/gogs)(IT)
@ -90,7 +92,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。 - 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。 - 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
- 感谢 [Rocker](http://weibo.com/rocker1989) 设计的 Logo。 - 感谢 [Egon Elbre](https://twitter.com/egonelbre) 设计的 Logo。
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。 - 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。 - 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
- 感谢 [KeyCDN](https://www.keycdn.com/) 和 [七牛云存储](http://www.qiniu.com/) 提供 CDN 服务赞助。 - 感谢 [KeyCDN](https://www.keycdn.com/) 和 [七牛云存储](http://www.qiniu.com/) 提供 CDN 服务赞助。

2
appveyor.yml

@ -11,7 +11,7 @@ build: false
deploy: false deploy: false
install: install:
- go get -t -v ./... - go build -v
notifications: notifications:
- provider: Email - provider: Email

14
cmd/dump.go

@ -14,6 +14,7 @@ import (
"io/ioutil" "io/ioutil"
"github.com/Unknwon/cae/zip" "github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
@ -87,9 +88,22 @@ func runDump(ctx *cli.Context) error {
} else { } else {
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath) log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
} }
if err := z.AddDir("log", setting.LogRootPath); err != nil { if err := z.AddDir("log", setting.LogRootPath); err != nil {
log.Fatalf("Fail to include log: %v", err) log.Fatalf("Fail to include log: %v", err)
} }
for _, dir := range []string{"attachments", "avatars"} {
dirPath := path.Join(setting.AppDataPath, dir)
if !com.IsDir(dirPath) {
continue
}
if err := z.AddDir(path.Join("data", dir), dirPath); err != nil {
log.Fatalf("Fail to include '%s': %v", dirPath, err)
}
}
// FIXME: SSH key file. // FIXME: SSH key file.
if err = z.Close(); err != nil { if err = z.Close(); err != nil {
os.Remove(fileName) os.Remove(fileName)

140
cmd/hook.go

@ -0,0 +1,140 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"bufio"
"bytes"
"os"
"os/exec"
"path/filepath"
"github.com/Unknwon/com"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
)
var (
CmdHook = cli.Command{
Name: "hook",
Usage: "Delegate commands to corresponding Git hooks",
Description: "All sub-commands should only be called by Git",
Flags: []cli.Flag{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
},
Subcommands: []cli.Command{
subcmdHookPreReceive,
subcmdHookUpadte,
subcmdHookPostReceive,
},
}
subcmdHookPreReceive = cli.Command{
Name: "pre-receive",
Usage: "Delegate pre-receive Git hook",
Description: "This command should only be called by Git",
Action: runHookPreReceive,
}
subcmdHookUpadte = cli.Command{
Name: "update",
Usage: "Delegate update Git hook",
Description: "This command should only be called by Git",
Action: runHookUpdate,
}
subcmdHookPostReceive = cli.Command{
Name: "post-receive",
Usage: "Delegate post-receive Git hook",
Description: "This command should only be called by Git",
Action: runHookPostReceive,
}
)
func runHookPreReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
setup(c, "hooks/pre-receive.log")
buf := bytes.NewBuffer(nil)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
buf.Write(scanner.Bytes())
buf.WriteByte('\n')
}
customHooksPath := os.Getenv(_ENV_REPO_CUSTOM_HOOKS_PATH)
if !com.IsFile(customHooksPath) {
return nil
}
hookCmd := exec.Command(filepath.Join(customHooksPath, "pre-receive"))
hookCmd.Stdout = os.Stdout
hookCmd.Stdin = buf
hookCmd.Stderr = os.Stderr
if err := hookCmd.Run(); err != nil {
fail("Internal error", "Fail to execute custom pre-receive hook: %v", err)
}
return nil
}
func runHookUpdate(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
setup(c, "hooks/update.log")
args := c.Args()
if len(args) != 3 {
fail("Arguments received are not equal to three", "Arguments received are not equal to three")
} else if len(args[0]) == 0 {
fail("First argument 'refName' is empty", "First argument 'refName' is empty")
}
uuid := os.Getenv(_ENV_UPDATE_TASK_UUID)
if err := models.AddUpdateTask(&models.UpdateTask{
UUID: uuid,
RefName: args[0],
OldCommitID: args[1],
NewCommitID: args[2],
}); err != nil {
fail("Internal error", "Fail to add update task '%s': %v", uuid, err)
}
customHooksPath := os.Getenv(_ENV_REPO_CUSTOM_HOOKS_PATH)
if !com.IsFile(customHooksPath) {
return nil
}
hookCmd := exec.Command(filepath.Join(customHooksPath, "update"), args...)
hookCmd.Stdout = os.Stdout
hookCmd.Stdin = os.Stdin
hookCmd.Stderr = os.Stderr
if err := hookCmd.Run(); err != nil {
fail("Internal error", "Fail to execute custom pre-receive hook: %v", err)
}
return nil
}
func runHookPostReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
setup(c, "hooks/post-receive.log")
customHooksPath := os.Getenv(_ENV_REPO_CUSTOM_HOOKS_PATH)
if !com.IsFile(customHooksPath) {
return nil
}
hookCmd := exec.Command(filepath.Join(customHooksPath, "post-receive"))
hookCmd.Stdout = os.Stdout
hookCmd.Stdin = os.Stdin
hookCmd.Stderr = os.Stderr
if err := hookCmd.Run(); err != nil {
fail("Internal error", "Fail to execute custom post-receive hook: %v", err)
}
return nil
}

196
cmd/serve.go → cmd/serv.go

@ -14,22 +14,24 @@ import (
"time" "time"
"github.com/Unknwon/com" "github.com/Unknwon/com"
git "github.com/gogits/git-module" "github.com/gogits/git-module"
gouuid "github.com/satori/go.uuid" gouuid "github.com/satori/go.uuid"
"github.com/urfave/cli" "github.com/urfave/cli"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/httplib" "github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const ( const (
_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access" _ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
_ENV_UPDATE_TASK_UUID = "UPDATE_TASK_UUID"
_ENV_REPO_CUSTOM_HOOKS_PATH = "REPO_CUSTOM_HOOKS_PATH"
) )
var CmdServ = cli.Command{ var Serv = cli.Command{
Name: "serv", Name: "serv",
Usage: "This command should only be called by SSH shell", Usage: "This command should only be called by SSH shell",
Description: `Serv provide access auth for repositories`, Description: `Serv provide access auth for repositories`,
@ -39,13 +41,28 @@ var CmdServ = cli.Command{
}, },
} }
func setup(logPath string) { func setup(c *cli.Context, logPath string) {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
} else if c.GlobalIsSet("config") {
setting.CustomConf = c.GlobalString("config")
}
setting.NewContext() setting.NewContext()
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath)) setting.NewService()
log.New(log.FILE, log.FileConfig{
Filename: filepath.Join(setting.LogRootPath, logPath),
FileRotationConfig: log.FileRotationConfig{
Rotate: true,
Daily: true,
MaxDays: 3,
},
})
log.Delete(log.CONSOLE) // Remove primary logger
models.LoadConfigs() models.LoadConfigs()
if setting.UseSQLite3 || setting.UseTiDB { if setting.UseSQLite3 {
workDir, _ := setting.WorkDir() workDir, _ := setting.WorkDir()
os.Chdir(workDir) os.Chdir(workDir)
} }
@ -53,7 +70,7 @@ func setup(logPath string) {
models.SetEngine() models.SetEngine()
} }
func parseCmd(cmd string) (string, string) { func parseSSHCmd(cmd string) (string, string) {
ss := strings.SplitN(cmd, " ", 2) ss := strings.SplitN(cmd, " ", 2)
if len(ss) != 2 { if len(ss) != 2 {
return "", "" return "", ""
@ -61,6 +78,24 @@ func parseCmd(cmd string) (string, string) {
return ss[0], strings.Replace(ss[1], "'/", "'", 1) return ss[0], strings.Replace(ss[1], "'/", "'", 1)
} }
func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
// Check if this deploy key belongs to current repository.
if !models.HasDeployKey(key.ID, repo.ID) {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
// Update deploy key activity.
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
fail("Internal error", "GetDeployKey: %v", err)
}
deployKey.Updated = time.Now()
if err = models.UpdateDeployKey(deployKey); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err)
}
}
var ( var (
allowedCommands = map[string]models.AccessMode{ allowedCommands = map[string]models.AccessMode{
"git-upload-pack": models.ACCESS_MODE_READ, "git-upload-pack": models.ACCESS_MODE_READ,
@ -76,11 +111,10 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode { if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...) fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
} }
log.GitLogger.Fatal(3, logMessage, args...) log.Fatal(3, logMessage, args...)
return
} }
log.GitLogger.Close() log.Shutdown()
os.Exit(1) os.Exit(1)
} }
@ -88,12 +122,12 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
task, err := models.GetUpdateTaskByUUID(uuid) task, err := models.GetUpdateTaskByUUID(uuid)
if err != nil { if err != nil {
if models.IsErrUpdateTaskNotExist(err) { if models.IsErrUpdateTaskNotExist(err) {
log.GitLogger.Trace("No update task is presented: %s", uuid) log.Trace("No update task is presented: %s", uuid)
return return
} }
log.GitLogger.Fatal(2, "GetUpdateTaskByUUID: %v", err) log.Fatal(2, "GetUpdateTaskByUUID: %v", err)
} else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil { } else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
log.GitLogger.Fatal(2, "DeleteUpdateTaskByUUID: %v", err) log.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
} }
if isWiki { if isWiki {
@ -109,13 +143,13 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
RepoUserName: repoUser.Name, RepoUserName: repoUser.Name,
RepoName: reponame, RepoName: reponame,
}); err != nil { }); err != nil {
log.GitLogger.Error(2, "Update: %v", err) log.Error(2, "Update: %v", err)
} }
// Ask for running deliver hook and test pull request tasks. // Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" + reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID) strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
log.GitLogger.Trace("Trigger task: %s", reqURL) log.Trace("Trigger task: %s", reqURL)
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{ resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
@ -123,19 +157,15 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
if err == nil { if err == nil {
resp.Body.Close() resp.Body.Close()
if resp.StatusCode/100 != 2 { if resp.StatusCode/100 != 2 {
log.GitLogger.Error(2, "Fail to trigger task: not 2xx response code") log.Error(2, "Fail to trigger task: not 2xx response code")
} }
} else { } else {
log.GitLogger.Error(2, "Fail to trigger task: %v", err) log.Error(2, "Fail to trigger task: %v", err)
} }
} }
func runServ(c *cli.Context) error { func runServ(c *cli.Context) error {
if c.IsSet("config") { setup(c, "serv.log")
setting.CustomConf = c.String("config")
}
setup("serv.log")
if setting.SSH.Disabled { if setting.SSH.Disabled {
println("Gogs: SSH has been disabled") println("Gogs: SSH has been disabled")
@ -146,21 +176,21 @@ func runServ(c *cli.Context) error {
fail("Not enough arguments", "Not enough arguments") fail("Not enough arguments", "Not enough arguments")
} }
cmd := os.Getenv("SSH_ORIGINAL_COMMAND") sshCmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 { if len(sshCmd) == 0 {
println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.") println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
println("If this is unexpected, please log in with password and setup Gogs under another user.") println("If this is unexpected, please log in with password and setup Gogs under another user.")
return nil return nil
} }
verb, args := parseCmd(cmd) verb, args := parseSSHCmd(sshCmd)
repoPath := strings.ToLower(strings.Trim(args, "'")) repoFullName := strings.ToLower(strings.Trim(args, "'"))
rr := strings.SplitN(repoPath, "/", 2) repoFields := strings.SplitN(repoFullName, "/", 2)
if len(rr) != 2 { if len(repoFields) != 2 {
fail("Invalid repository path", "Invalid repository path: %v", args) fail("Invalid repository path", "Invalid repository path: %v", args)
} }
username := strings.ToLower(rr[0]) username := strings.ToLower(repoFields[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git")) reponame := strings.ToLower(strings.TrimSuffix(repoFields[1], ".git"))
isWiki := false isWiki := false
if strings.HasSuffix(reponame, ".wiki") { if strings.HasSuffix(reponame, ".wiki") {
@ -168,122 +198,112 @@ func runServ(c *cli.Context) error {
reponame = reponame[:len(reponame)-5] reponame = reponame[:len(reponame)-5]
} }
repoUser, err := models.GetUserByName(username) repoOwner, err := models.GetUserByName(username)
if err != nil { if err != nil {
if models.IsErrUserNotExist(err) { if models.IsErrUserNotExist(err) {
fail("Repository owner does not exist", "Unregistered owner: %s", username) fail("Repository owner does not exist", "Unregistered owner: %s", username)
} }
fail("Internal error", "Failed to get repository owner (%s): %v", username, err) fail("Internal error", "Fail to get repository owner '%s': %v", username, err)
} }
repo, err := models.GetRepositoryByName(repoUser.ID, reponame) repo, err := models.GetRepositoryByName(repoOwner.ID, reponame)
if err != nil { if err != nil {
if models.IsErrRepoNotExist(err) { if models.IsErrRepoNotExist(err) {
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, reponame) fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoOwner.Name, reponame)
} }
fail("Internal error", "Failed to get repository: %v", err) fail("Internal error", "Fail to get repository: %v", err)
} }
repo.Owner = repoOwner
requestedMode, has := allowedCommands[verb] requestMode, ok := allowedCommands[verb]
if !has { if !ok {
fail("Unknown git command", "Unknown git command %s", verb) fail("Unknown git command", "Unknown git command '%s'", verb)
} }
// Prohibit push to mirror repositories. // Prohibit push to mirror repositories.
if requestedMode > models.ACCESS_MODE_READ && repo.IsMirror { if requestMode > models.ACCESS_MODE_READ && repo.IsMirror {
fail("mirror repository is read-only", "") fail("mirror repository is read-only", "")
} }
// Allow anonymous clone for public repositories. // Allow anonymous (user is nil) clone for public repositories.
var ( var user *models.User
keyID int64
user *models.User
)
if requestedMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64()) key, err := models.GetPublicKeyByID(com.StrTo(strings.TrimPrefix(c.Args()[0], "key-")).MustInt64())
if err != nil { if err != nil {
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err) fail("Invalid key ID", "Invalid key ID '%s': %v", c.Args()[0], err)
} }
keyID = key.ID
if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
// Check deploy key or user key. // Check deploy key or user key.
if key.Type == models.KEY_TYPE_DEPLOY { if key.IsDeployKey() {
if key.Mode < requestedMode { if key.Mode < requestMode {
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID) fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
} }
// Check if this deploy key belongs to current repository. checkDeployKey(key, repo)
if !models.HasDeployKey(key.ID, repo.ID) {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
// Update deploy key activity.
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
fail("Internal error", "GetDeployKey: %v", err)
}
deployKey.Updated = time.Now()
if err = models.UpdateDeployKey(deployKey); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err)
}
} else { } else {
user, err = models.GetUserByKeyID(key.ID) user, err = models.GetUserByKeyID(key.ID)
if err != nil { if err != nil {
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err) fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
} }
mode, err := models.AccessLevel(user, repo) mode, err := models.AccessLevel(user, repo)
if err != nil { if err != nil {
fail("Internal error", "Fail to check access: %v", err) fail("Internal error", "Fail to check access: %v", err)
} else if mode < requestedMode { }
if mode < requestMode {
clientMessage := _ACCESS_DENIED_MESSAGE clientMessage := _ACCESS_DENIED_MESSAGE
if mode >= models.ACCESS_MODE_READ { if mode >= models.ACCESS_MODE_READ {
clientMessage = "You do not have sufficient authorization for this action" clientMessage = "You do not have sufficient authorization for this action"
} }
fail(clientMessage, fail(clientMessage,
"User %s does not have level %v access to repository %s", "User '%s' does not have level '%v' access to repository '%s'",
user.Name, requestedMode, repoPath) user.Name, requestMode, repoFullName)
} }
} }
} else {
// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
// we should give read access only in repositories where this deploy key is in use. In other case, a server
// or system using an active deploy key can get read access to all the repositories in a Gogs service.
if key.IsDeployKey() && setting.Service.RequireSignInView {
checkDeployKey(key, repo)
}
} }
uuid := gouuid.NewV4().String() uuid := gouuid.NewV4().String()
os.Setenv("uuid", uuid) os.Setenv(_ENV_UPDATE_TASK_UUID, uuid)
os.Setenv(_ENV_REPO_CUSTOM_HOOKS_PATH, filepath.Join(repo.RepoPath(), "custom_hooks"))
// Special handle for Windows. // Special handle for Windows.
if setting.IsWindows { if setting.IsWindows {
verb = strings.Replace(verb, "-", " ", 1) verb = strings.Replace(verb, "-", " ", 1)
} }
var gitcmd *exec.Cmd var gitCmd *exec.Cmd
verbs := strings.Split(verb, " ") verbs := strings.Split(verb, " ")
if len(verbs) == 2 { if len(verbs) == 2 {
gitcmd = exec.Command(verbs[0], verbs[1], repoPath) gitCmd = exec.Command(verbs[0], verbs[1], repoFullName)
} else { } else {
gitcmd = exec.Command(verb, repoPath) gitCmd = exec.Command(verb, repoFullName)
} }
gitcmd.Dir = setting.RepoRootPath gitCmd.Dir = setting.RepoRootPath
gitcmd.Stdout = os.Stdout gitCmd.Stdout = os.Stdout
gitcmd.Stdin = os.Stdin gitCmd.Stdin = os.Stdin
gitcmd.Stderr = os.Stderr gitCmd.Stderr = os.Stderr
if err = gitcmd.Run(); err != nil { if err = gitCmd.Run(); err != nil {
fail("Internal error", "Failed to execute git command: %v", err) fail("Internal error", "Fail to execute git command: %v", err)
} }
if requestedMode == models.ACCESS_MODE_WRITE { if requestMode == models.ACCESS_MODE_WRITE {
handleUpdateTask(uuid, user, repoUser, reponame, isWiki) handleUpdateTask(uuid, user, repoOwner, reponame, isWiki)
} }
// Update user key activity. // Update user key activity.
if keyID > 0 { if key.ID > 0 {
key, err := models.GetPublicKeyByID(keyID) key, err := models.GetPublicKeyByID(key.ID)
if err != nil { if err != nil {
fail("Internal error", "GetPublicKeyById: %v", err) fail("Internal error", "GetPublicKeyByID: %v", err)
} }
key.Updated = time.Now() key.Updated = time.Now()

58
cmd/update.go

@ -1,58 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"os"
"github.com/urfave/cli"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
var CmdUpdate = cli.Command{
Name: "update",
Usage: "This command should only be called by Git hook",
Description: `Update get pushed info and insert into database`,
Action: runUpdate,
Flags: []cli.Flag{
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
},
}
func runUpdate(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
setup("update.log")
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
return nil
}
args := c.Args()
if len(args) != 3 {
log.GitLogger.Fatal(2, "Arguments received are not equal to three")
} else if len(args[0]) == 0 {
log.GitLogger.Fatal(2, "First argument 'refName' is empty, shouldn't use")
}
task := models.UpdateTask{
UUID: os.Getenv("uuid"),
RefName: args[0],
OldCommitID: args[1],
NewCommitID: args[2],
}
if err := models.AddUpdateTask(&task); err != nil {
log.GitLogger.Fatal(2, "AddUpdateTask: %v", err)
}
return nil
}

31
cmd/web.go

@ -26,6 +26,7 @@ import (
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/mcuadros/go-version" "github.com/mcuadros/go-version"
"github.com/urfave/cli" "github.com/urfave/cli"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
@ -36,7 +37,6 @@ import (
"github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/bindata" "github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/context" "github.com/gogits/gogs/modules/context"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template" "github.com/gogits/gogs/modules/template"
@ -84,6 +84,7 @@ func checkVersion() {
} }
// Check dependency version. // Check dependency version.
// LEGACY [0.11]: no need to check version as we check in vendor into version control
checkers := []VerChecker{ checkers := []VerChecker{
{"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.6.0"}, {"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.6.0"},
{"github.com/go-macaron/binding", binding.Version, "0.3.2"}, {"github.com/go-macaron/binding", binding.Version, "0.3.2"},
@ -94,7 +95,7 @@ func checkVersion() {
{"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"}, {"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"},
{"gopkg.in/ini.v1", ini.Version, "1.8.4"}, {"gopkg.in/ini.v1", ini.Version, "1.8.4"},
{"gopkg.in/macaron.v1", macaron.Version, "1.1.7"}, {"gopkg.in/macaron.v1", macaron.Version, "1.1.7"},
{"github.com/gogits/git-module", git.Version, "0.4.6"}, {"github.com/gogits/git-module", git.Version, "0.4.7"},
{"github.com/gogits/go-gogs-client", gogs.Version, "0.12.1"}, {"github.com/gogits/go-gogs-client", gogs.Version, "0.12.1"},
} }
for _, c := range checkers { for _, c := range checkers {
@ -362,8 +363,14 @@ func runWeb(ctx *cli.Context) error {
// ***** START: Organization ***** // ***** START: Organization *****
m.Group("/org", func() { m.Group("/org", func() {
m.Group("", func() {
m.Get("/create", org.Create) m.Get("/create", org.Create)
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
}, func(ctx *context.Context) {
if !ctx.User.CanCreateOrganization() {
ctx.NotFound()
}
})
m.Group("/:org", func() { m.Group("/:org", func() {
m.Get("/dashboard", user.Dashboard) m.Get("/dashboard", user.Dashboard)
@ -525,6 +532,10 @@ func runWeb(ctx *cli.Context) error {
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
}) })
// FIXME: Should use ctx.Repo.PullRequest to unify template, currently we have inconsistent URL
// for PR in same repository. After select branch on the page, the URL contains redundant head user name.
// e.g. /org1/test-repo/compare/master...org1:develop
// which should be /org1/test-repo/compare/master...develop
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest). m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
@ -566,7 +577,7 @@ func runWeb(ctx *cli.Context) error {
}, context.RepoRef()) }, context.RepoRef())
// m.Get("/branches", repo.Branches) // m.Get("/branches", repo.Branches)
m.Post("/branches/:name/delete", reqSignIn, reqRepoWriter, repo.DeleteBranchPost) m.Post("/branches/delete/*", reqSignIn, reqRepoWriter, repo.DeleteBranchPost)
m.Group("/wiki", func() { m.Group("/wiki", func() {
m.Get("/?:page", repo.Wiki) m.Get("/?:page", repo.Wiki)
@ -598,7 +609,7 @@ func runWeb(ctx *cli.Context) error {
}, context.RepoRef()) }, context.RepoRef())
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff) m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.CompareDiff) m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", context.RepoRef(), repo.CompareDiff)
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare) }, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars) m.Get("/stars", repo.Stars)
@ -653,7 +664,17 @@ func runWeb(ctx *cli.Context) error {
case setting.SCHEME_HTTP: case setting.SCHEME_HTTP:
err = http.ListenAndServe(listenAddr, m) err = http.ListenAndServe(listenAddr, m)
case setting.SCHEME_HTTPS: case setting.SCHEME_HTTPS:
server := &http.Server{Addr: listenAddr, TLSConfig: &tls.Config{MinVersion: tls.VersionTLS10}, Handler: m} server := &http.Server{Addr: listenAddr, TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS10,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // Required for HTTP/2 support.
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
},
}, Handler: m}
err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile) err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
case setting.SCHEME_FCGI: case setting.SCHEME_FCGI:
err = fcgi.Serve(nil, m) err = fcgi.Serve(nil, m)

127
conf/app.ini

@ -52,34 +52,6 @@ FILE_MAX_SIZE = 3
; Maximum number of files per upload ; Maximum number of files per upload
MAX_FILES = 5 MAX_FILES = 5
[ui]
; Number of repositories that are showed in one explore page
EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page
ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed
FEED_MAX_COMMIT_NUM = 5
; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#ff5343`
; Max size of files to be displayed (defaults is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608
[ui.admin]
; Number of users that are showed in one page
USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[ui.user]
; Number of repos that are showed in one page
REPO_PAGING_NUM = 15
[markdown] [markdown]
; Enable hard line break extension ; Enable hard line break extension
ENABLE_HARD_LINE_BREAK = false ENABLE_HARD_LINE_BREAK = false
@ -106,16 +78,18 @@ LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
DISABLE_SSH = false DISABLE_SSH = false
; Whether use builtin SSH server or not. ; Whether use builtin SSH server or not.
START_SSH_SERVER = false START_SSH_SERVER = false
; Domain name to be exposed in clone URL ; Domain name to be exposed in SSH clone URL
SSH_DOMAIN = %(DOMAIN)s SSH_DOMAIN = %(DOMAIN)s
; Port number to be exposed in SSH clone URL
SSH_PORT = 22
; Network interface builtin SSH server listens on ; Network interface builtin SSH server listens on
SSH_LISTEN_HOST = 0.0.0.0 SSH_LISTEN_HOST = 0.0.0.0
; Port number to be exposed in clone URL
SSH_PORT = 22
; Port number builtin SSH server listens on ; Port number builtin SSH server listens on
SSH_LISTEN_PORT = %(SSH_PORT)s SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH = SSH_ROOT_PATH =
; Choose the ciphers to support for SSH connections
SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128
; Directory to create temporary files when test publick key using ssh-keygen, ; Directory to create temporary files when test publick key using ssh-keygen,
; default is system temporary directory. ; default is system temporary directory.
SSH_KEY_TEST_PATH = SSH_KEY_TEST_PATH =
@ -157,7 +131,7 @@ RSA = 2048
DSA = 1024 DSA = 1024
[database] [database]
; Either "mysql", "postgres" or "sqlite3", it's your choice ; Either "mysql", "postgres" or "sqlite3", you can connect to TiDB with MySQL protocol
DB_TYPE = mysql DB_TYPE = mysql
HOST = 127.0.0.1:3306 HOST = 127.0.0.1:3306
NAME = gogs NAME = gogs
@ -169,6 +143,8 @@ SSL_MODE = disable
PATH = data/gogs.db PATH = data/gogs.db
[admin] [admin]
; Disable regular (non-admin) users to create organizations
DISABLE_REGULAR_ORG_CREATION = false
[security] [security]
INSTALL_LOCK = false INSTALL_LOCK = false
@ -178,6 +154,7 @@ SECRET_KEY = !#@FDEWREWR&*(
LOGIN_REMEMBER_DAYS = 7 LOGIN_REMEMBER_DAYS = 7
COOKIE_USERNAME = gogs_awesome COOKIE_USERNAME = gogs_awesome
COOKIE_REMEMBER_NAME = gogs_incredible COOKIE_REMEMBER_NAME = gogs_incredible
COOKIE_SECURE = false
; Reverse proxy authentication header name of user name ; Reverse proxy authentication header name of user name
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
@ -268,6 +245,7 @@ GC_INTERVAL_TIME = 86400
SESSION_LIFE_TIME = 86400 SESSION_LIFE_TIME = 86400
[picture] [picture]
; Path to store user uploaded avatars
AVATAR_UPLOAD_PATH = data/avatars AVATAR_UPLOAD_PATH = data/avatars
; Chinese users can choose "duoshuo" ; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/ ; or a custom avatar source, like: http://cn.gravatar.com/avatar/
@ -297,66 +275,43 @@ MAX_FILES = 5
; For more information about the format see http://golang.org/pkg/time/#pkg-constants ; For more information about the format see http://golang.org/pkg/time/#pkg-constants
FORMAT = FORMAT =
; General settings of loggers
[log] [log]
ROOT_PATH = ROOT_PATH =
; Either "console", "file", "conn", "smtp" or "database", default is "console" ; Can be "console" and "file", default is "console"
; Use comma to separate multiple modes, e.g. "console, file" ; Use comma to separate multiple modes, e.g. "console, file"
MODE = console MODE = console
; Buffer length of channel, keep it as it is if you don't know what it is. ; Buffer length of channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000 BUFFER_LEN = 100
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" ; Either "Trace", "Info", "Warn", "Error", "Fatal", default is "Trace"
LEVEL = Trace LEVEL = Trace
; For "console" mode only ; For "console" mode only
[log.console] [log.console]
; leave empty to inherit
LEVEL = LEVEL =
; For "file" mode only ; For "file" mode only
[log.file] [log.file]
; leave empty to inherit
LEVEL = LEVEL =
; This enables automated log rotate(switch of following options), default is true ; This enables automated log rotate (switch of following options)
LOG_ROTATE = true LOG_ROTATE = true
; Max line number of single file, default is 1000000 ; Segment log daily
MAX_LINES = 1000000 DAILY_ROTATE = true
; Max size shift of single file, default is 28 means 1 << 28, 256MB ; Max size shift of single file, default is 28 means 1 << 28, 256MB
MAX_SIZE_SHIFT = 28 MAX_SIZE_SHIFT = 28
; Segment log daily, default is true ; Max line number of single file
DAILY_ROTATE = true MAX_LINES = 1000000
; Expired days of log file(delete after max days), default is 7 ; Expired days of log file (delete after max days)
MAX_DAYS = 7 MAX_DAYS = 7
; For "conn" mode only ; For "slack" mode only
[log.conn] [log.slack]
LEVEL = ; leave empty to inherit
; Reconnect host for every single message, default is false
RECONNECT_ON_MSG = false
; Try to reconnect when connection is lost, default is false
RECONNECT = false
; Either "tcp", "unix" or "udp", default is "tcp"
PROTOCOL = tcp
; Host address
ADDR =
; For "smtp" mode only
[log.smtp]
LEVEL = LEVEL =
; Name displayed in mail title, default is "Diagnostic message from server" ; Webhook URL
SUBJECT = Diagnostic message from server URL =
; Mail server
HOST =
; Mailer user name and password
USER =
PASSWD =
; Receivers, can be one or more, e.g. 1@example.com,2@example.com
RECEIVERS =
; For "database" mode only
[log.database]
LEVEL =
; Either "mysql" or "postgres"
DRIVER =
; Based on xorm, e.g.: root:root@localhost/gogs?charset=utf8
CONN =
[cron] [cron]
; Enable running cron tasks periodically. ; Enable running cron tasks periodically.
@ -410,6 +365,34 @@ DEFAULT_INTERVAL = 8
; Max number of items will response in a page ; Max number of items will response in a page
MAX_RESPONSE_ITEMS = 50 MAX_RESPONSE_ITEMS = 50
[ui]
; Number of repositories that are showed in one explore page
EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page
ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed
FEED_MAX_COMMIT_NUM = 5
; Value of "theme-color" meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#ff5343`
; Max size in bytes of files to be displayed (default is 8MB)
MAX_DISPLAY_FILE_SIZE = 8388608
[ui.admin]
; Number of users that are showed in one page
USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[ui.user]
; Number of repos that are showed in one page
REPO_PAGING_NUM = 15
[i18n] [i18n]
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego

4
conf/locale/locale_bg-BG.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Вашата версия не поддържа SQLite3,
invalid_db_setting=Настройките на базата данни са некоректни: %v invalid_db_setting=Настройките на базата данни са некоректни: %v
invalid_repo_path=Основният път към хранилищата е невалиден: %v invalid_repo_path=Основният път към хранилищата е невалиден: %v
run_user_not_match=Потребителският контекст на приложението не е на текущия потребител: %s -> %s run_user_not_match=Потребителският контекст на приложението не е на текущия потребител: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Неуспешно запазване на конфигурация: %v save_config_failed=Неуспешно запазване на конфигурация: %v
invalid_admin_setting=Настройките на профил на администратора са невалидни: %v invalid_admin_setting=Настройките на профил на администратора са невалидни: %v
install_success=Добре дошли! Радваме се, че избрахте Gogs, и Ви пожелаваме приятна работа и сърдечни поздрави! install_success=Добре дошли! Радваме се, че избрахте Gogs, и Ви пожелаваме приятна работа и сърдечни поздрави!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Посетителите ще бъдат пре
settings.issues_desc=Включи система за проследяване на задачи settings.issues_desc=Включи система за проследяване на задачи
settings.use_internal_issue_tracker=Изполвай вградена система за проследяване на задачи settings.use_internal_issue_tracker=Изполвай вградена система за проследяване на задачи
settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи settings.use_external_issue_tracker=Използвай външна система за проследяване на задачи
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи settings.tracker_url_format=Формат на URL адрес на външна система за проследяване на задачи
settings.tracker_issue_style=Стил на именуване на външна система за проследяване на задачи: settings.tracker_issue_style=Стил на именуване на външна система за проследяване на задачи:
settings.tracker_issue_style.numeric=Цифров settings.tracker_issue_style.numeric=Цифров
@ -1048,6 +1051,7 @@ config.offline_mode=Офлайн режим
config.disable_router_log=Изключи журнал на маршрутизатора config.disable_router_log=Изключи журнал на маршрутизатора
config.run_user=Потребителски контекст config.run_user=Потребителски контекст
config.run_mode=Режим на изпълнение config.run_mode=Режим на изпълнение
config.git_version=Git Version
config.repo_root_path=Основен път към хранилища config.repo_root_path=Основен път към хранилища
config.static_file_root_path=Път към статични файлове config.static_file_root_path=Път към статични файлове
config.log_file_root_path=Път към журнал config.log_file_root_path=Път към журнал

4
conf/locale/locale_cs-CZ.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Vaše verze vydání Gogs nepodporuje SQLite3, prosíme st
invalid_db_setting=Nastavení databáze není správné: %v invalid_db_setting=Nastavení databáze není správné: %v
invalid_repo_path=Kořenový adresář repositáře není správný: %v invalid_repo_path=Kořenový adresář repositáře není správný: %v
run_user_not_match=Uživatel pro spuštění není aktuální uživatel: %s -> %s run_user_not_match=Uživatel pro spuštění není aktuální uživatel: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Uložení konfigurace se nezdařilo: %v save_config_failed=Uložení konfigurace se nezdařilo: %v
invalid_admin_setting=Nastavení účtu správce není správné: %v invalid_admin_setting=Nastavení účtu správce není správné: %v
install_success=Vítejte! Jsme rádi, že jste si vybrali Gogs. Bavte se a opatrujte se. install_success=Vítejte! Jsme rádi, že jste si vybrali Gogs. Bavte se a opatrujte se.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Návštěvníci budou při kliknutí na záložk
settings.issues_desc=Povolit systém úkolů settings.issues_desc=Povolit systém úkolů
settings.use_internal_issue_tracker=Povolit věstavěný odlehčený systém úkolů settings.use_internal_issue_tracker=Povolit věstavěný odlehčený systém úkolů
settings.use_external_issue_tracker=Použít externí systém úkolů settings.use_external_issue_tracker=Použít externí systém úkolů
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formát URL externího systému úkolů settings.tracker_url_format=Formát URL externího systému úkolů
settings.tracker_issue_style=Styl pojmenování externího systému úkolů: settings.tracker_issue_style=Styl pojmenování externího systému úkolů:
settings.tracker_issue_style.numeric=Číselný settings.tracker_issue_style.numeric=Číselný
@ -1048,6 +1051,7 @@ config.offline_mode=Režim off-line
config.disable_router_log=Vypnout log směrovače config.disable_router_log=Vypnout log směrovače
config.run_user=Účet pro spouštění config.run_user=Účet pro spouštění
config.run_mode=Režim spouštění config.run_mode=Režim spouštění
config.git_version=Git Version
config.repo_root_path=Kořenový adresář repositářů config.repo_root_path=Kořenový adresář repositářů
config.static_file_root_path=Kořenový adresář statického souboru config.static_file_root_path=Kořenový adresář statického souboru
config.log_file_root_path=Kořenový adresář souboru logu config.log_file_root_path=Kořenový adresář souboru logu

12
conf/locale/locale_de-DE.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Ihre Gogs-Version unterstützt SQLite3 nicht. Bitte laden
invalid_db_setting=Datenbankeinstellungen sind nicht korrekt: %v invalid_db_setting=Datenbankeinstellungen sind nicht korrekt: %v
invalid_repo_path=Repository Verzeichnis ist ungültig: %v invalid_repo_path=Repository Verzeichnis ist ungültig: %v
run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Fehler beim Speichern der Konfiguration: %v save_config_failed=Fehler beim Speichern der Konfiguration: %v
invalid_admin_setting=Admin-Konto Einstellungen sind ungültig: %v invalid_admin_setting=Admin-Konto Einstellungen sind ungültig: %v
install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für Gogs entschieden haben. Wir wünschen viel Vergnügen damit. install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für Gogs entschieden haben. Wir wünschen viel Vergnügen damit.
@ -338,8 +339,8 @@ access_token_deletion_desc=Das Löschen dieses persönlichen Zugangs-Tokens wird
delete_token_success=Persönlicher Zugriffs-Token wurde erfolgreich entfernt! Vergessen Sie nicht Ihre Anwendung zu aktualisieren. delete_token_success=Persönlicher Zugriffs-Token wurde erfolgreich entfernt! Vergessen Sie nicht Ihre Anwendung zu aktualisieren.
orgs.none=Sie sind kein Mitglied einer Organisation. orgs.none=Sie sind kein Mitglied einer Organisation.
orgs.leave_title=Leave an organization orgs.leave_title=Organisation verlassen
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue? orgs.leave_desc=Sie verlieren den Zugriff auf alle Repositories und Teams nach dem Verlassen der Organisation. Möchten Sie fortfahren?
delete_account=Konto löschen delete_account=Konto löschen
delete_prompt=Diese Aktion wird Ihr Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden! delete_prompt=Diese Aktion wird Ihr Konto dauerhaft löschen und kann <strong>NICHT</strong> rückgängig gemacht werden!
@ -388,8 +389,8 @@ migrate_type=Migrationstyp
migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein
migrate_repo=Repository migrieren migrate_repo=Repository migrieren
migrate.clone_address=Adresse kopieren migrate.clone_address=Adresse kopieren
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL. migrate.clone_address_desc=Dies kann eine HTTP/HTTPS/GIT-URL sein.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path. migrate.clone_address_desc_import_local=Du darfst ein Repository vom lokalen Serverpfad migrieren.
migrate.permission_denied=Ihnen fehlen die Rechte zum Importieren lokaler Repositories. migrate.permission_denied=Ihnen fehlen die Rechte zum Importieren lokaler Repositories.
migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner.
migrate.failed=Fehler bei Migration: %v migrate.failed=Fehler bei Migration: %v
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Besucher werden auf diese URL umgeleitet, wenn s
settings.issues_desc=Issue-Tracker einschalten settings.issues_desc=Issue-Tracker einschalten
settings.use_internal_issue_tracker=Eingebauten Issue-Tracker verwenden settings.use_internal_issue_tracker=Eingebauten Issue-Tracker verwenden
settings.use_external_issue_tracker=Externes Issue-System verwenden settings.use_external_issue_tracker=Externes Issue-System verwenden
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=URL-Format des externen Issue-Systems settings.tracker_url_format=URL-Format des externen Issue-Systems
settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers: settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers:
settings.tracker_issue_style.numeric=Numerisch settings.tracker_issue_style.numeric=Numerisch
@ -1048,6 +1051,7 @@ config.offline_mode=Offline-Modus
config.disable_router_log=Router-Log deaktivieren config.disable_router_log=Router-Log deaktivieren
config.run_user=Ausführender Benutzer config.run_user=Ausführender Benutzer
config.run_mode=Laufzeit-Modus config.run_mode=Laufzeit-Modus
config.git_version=Git Version
config.repo_root_path=Repository-Verzeichnis config.repo_root_path=Repository-Verzeichnis
config.static_file_root_path=Verzeichnis für statische Dateien config.static_file_root_path=Verzeichnis für statische Dateien
config.log_file_root_path=Log-Verzeichnis config.log_file_root_path=Log-Verzeichnis

7
conf/locale/locale_en-US.ini

@ -116,6 +116,7 @@ sqlite3_not_available = Your release version does not support SQLite3, please do
invalid_db_setting = Database setting is not correct: %v invalid_db_setting = Database setting is not correct: %v
invalid_repo_path = Repository root path is invalid: %v invalid_repo_path = Repository root path is invalid: %v
run_user_not_match = Run user isn't the current user: %s -> %s run_user_not_match = Run user isn't the current user: %s -> %s
invalid_smtp_from = SMTP From field is not valid: %v
save_config_failed = Fail to save configuration: %v save_config_failed = Fail to save configuration: %v
invalid_admin_setting = Admin account setting is invalid: %v invalid_admin_setting = Admin account setting is invalid: %v
install_success = Welcome! We're glad that you chose Gogs, have fun and take care. install_success = Welcome! We're glad that you chose Gogs, have fun and take care.
@ -826,6 +827,7 @@ team_permission_desc = What permission level should this team have?
form.name_reserved = Organization name '%s' is reserved. form.name_reserved = Organization name '%s' is reserved.
form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed. form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed.
form.team_name_reserved = Team name '%s' is reserved.
settings = Settings settings = Settings
settings.options = Options settings.options = Options
@ -916,8 +918,8 @@ dashboard.git_gc_repos = Do garbage collection on repositories
dashboard.git_gc_repos_success = All repositories have done garbage collection successfully. dashboard.git_gc_repos_success = All repositories have done garbage collection successfully.
dashboard.resync_all_sshkeys = Rewrite '.ssh/authorized_keys' file (caution: non-Gogs keys will be lost) dashboard.resync_all_sshkeys = Rewrite '.ssh/authorized_keys' file (caution: non-Gogs keys will be lost)
dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully. dashboard.resync_all_sshkeys_success = All public keys have been rewritten successfully.
dashboard.resync_all_update_hooks = Rewrite all update hook of repositories (needed when custom config path is changed) dashboard.resync_all_hooks = Resync pre-receive, update and post-receive hooks of all repositories.
dashboard.resync_all_update_hooks_success = All repositories' update hook have been rewritten successfully. dashboard.resync_all_hooks_success = All repositories' pre-receive, update and post-receive hooks have been resynced successfully.
dashboard.reinit_missing_repos = Reinitialize all repository records that lost Git files dashboard.reinit_missing_repos = Reinitialize all repository records that lost Git files
dashboard.reinit_missing_repos_success = All repository records that lost Git files have been reinitialized successfully. dashboard.reinit_missing_repos_success = All repository records that lost Git files have been reinitialized successfully.
@ -1050,6 +1052,7 @@ config.offline_mode = Offline Mode
config.disable_router_log = Disable Router Log config.disable_router_log = Disable Router Log
config.run_user = Run User config.run_user = Run User
config.run_mode = Run Mode config.run_mode = Run Mode
config.git_version = Git Version
config.repo_root_path = Repository Root Path config.repo_root_path = Repository Root Path
config.static_file_root_path = Static File Root Path config.static_file_root_path = Static File Root Path
config.log_file_root_path = Log File Root Path config.log_file_root_path = Log File Root Path

22
conf/locale/locale_es-ES.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Tu versión no soporta SQLite3, por favor descarga el bina
invalid_db_setting=La configuración de la base de datos no es correcta: %v invalid_db_setting=La configuración de la base de datos no es correcta: %v
invalid_repo_path=La ruta de la raíz del repositorio es inválida: %v invalid_repo_path=La ruta de la raíz del repositorio es inválida: %v
run_user_not_match=El usuario que está ejecutando la aplicación no es el usuario actual: %s -> %s run_user_not_match=El usuario que está ejecutando la aplicación no es el usuario actual: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Error al guardar la configuración: %v save_config_failed=Error al guardar la configuración: %v
invalid_admin_setting=La configuración de la cuenta de administración es inválida: %v invalid_admin_setting=La configuración de la cuenta de administración es inválida: %v
install_success=Bienvenido! Estamos encantados de que hayas escogido Gogs, diviértete y cuídate. install_success=Bienvenido! Estamos encantados de que hayas escogido Gogs, diviértete y cuídate.
@ -337,9 +338,9 @@ access_token_deletion=Borrado de Token de Acceso Personal
access_token_deletion_desc=Si elimina este token de acceso personal la aplicación asociada perderá el permiso de acceso. ¿Desea continuar? access_token_deletion_desc=Si elimina este token de acceso personal la aplicación asociada perderá el permiso de acceso. ¿Desea continuar?
delete_token_success=¡El token de acceso personal ha sido eliminado con éxito! No se olvide de actualizar también las aplicaciones asociadas. delete_token_success=¡El token de acceso personal ha sido eliminado con éxito! No se olvide de actualizar también las aplicaciones asociadas.
orgs.none=You are not a member of any organizations. orgs.none=No eres un miembro de ninguna organización.
orgs.leave_title=Leave an organization orgs.leave_title=Salir de una organización
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue? orgs.leave_desc=Perderá el acceso a todos los repositorios y equipos después dejar la organización. ¿Desea continuar?
delete_account=Elimina tu cuenta delete_account=Elimina tu cuenta
delete_prompt=La operación eliminará tu cuenta de forma permanente y ¡<strong>NO</strong> se puede deshacer! delete_prompt=La operación eliminará tu cuenta de forma permanente y ¡<strong>NO</strong> se puede deshacer!
@ -388,8 +389,8 @@ migrate_type=Tipo de migración
migrate_type_helper=Este repositorio será una <span class="text blue">réplica</span> migrate_type_helper=Este repositorio será una <span class="text blue">réplica</span>
migrate_repo=Migrar Repositorio migrate_repo=Migrar Repositorio
migrate.clone_address=Clonar dirección migrate.clone_address=Clonar dirección
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL. migrate.clone_address_desc=Esto puede ser una dirección URL HTTP/HTTPS/GIT.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path. migrate.clone_address_desc_import_local=También se le permite migrar un repositorio por la ruta del servidor local.
migrate.permission_denied=No te está permitido importar repositorios locales. migrate.permission_denied=No te está permitido importar repositorios locales.
migrate.invalid_local_path=Rutal local inválida, no existe o no es un directorio. migrate.invalid_local_path=Rutal local inválida, no existe o no es un directorio.
migrate.failed=Migración fallida: %v migrate.failed=Migración fallida: %v
@ -414,7 +415,7 @@ create_new_repo_command=Crear un nuevo repositorio desde línea de comandos
push_exist_repo=Hacer Push de un repositorio existente desde línea de comandos push_exist_repo=Hacer Push de un repositorio existente desde línea de comandos
repo_is_empty=Este repositorio está vacío, por favor, ¡vuelva más tarde! repo_is_empty=Este repositorio está vacío, por favor, ¡vuelva más tarde!
files=Files files=Archivos
branch=Rama branch=Rama
tree=Árbol tree=Árbol
filter_branch_and_tag=Filtrar por rama o etiqueta filter_branch_and_tag=Filtrar por rama o etiqueta
@ -529,7 +530,7 @@ issues.next=Página Siguiente
issues.open_title=Abierta issues.open_title=Abierta
issues.closed_title=Cerrada issues.closed_title=Cerrada
issues.num_comments=%d comentarios issues.num_comments=%d comentarios
issues.commented_at='comentado <a href="#%s"> %s'</a> issues.commented_at=`comentado <a href="#%s"> %s</a>`
issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario? issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario?
issues.no_content=Aún no existe contenido. issues.no_content=Aún no existe contenido.
issues.close_issue=Cerrar issues.close_issue=Cerrar
@ -587,7 +588,7 @@ pulls.cannot_auto_merge_helper=Por favor, fusiona manualmente para resolver los
pulls.merge_pull_request=Fusionar Pull Request pulls.merge_pull_request=Fusionar Pull Request
pulls.open_unmerged_pull_exists=`Usted no puede realizar la operación de reapertura porque en estos momentos existe una solicitud de pull request (#%d) para el mismo repositorio con la misma información que se encuentra a la espera de aprobación` pulls.open_unmerged_pull_exists=`Usted no puede realizar la operación de reapertura porque en estos momentos existe una solicitud de pull request (#%d) para el mismo repositorio con la misma información que se encuentra a la espera de aprobación`
pulls.delete_branch=Eliminar la rama pulls.delete_branch=Eliminar la rama
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence. pulls.delete_branch_has_new_commits=La rama no se puede eliminar porque tiene nuevos commits después de la fusión.
milestones.new=Nuevo Milestone milestones.new=Nuevo Milestone
milestones.open_tab=%d abiertas milestones.open_tab=%d abiertas
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Los visitantes serán redireccionados a la URL c
settings.issues_desc=Habilitar rastreo de incidencias settings.issues_desc=Habilitar rastreo de incidencias
settings.use_internal_issue_tracker=Usar rastreo de incidencias ligero incluido settings.use_internal_issue_tracker=Usar rastreo de incidencias ligero incluido
settings.use_external_issue_tracker=Usar tracker externo de incidencias settings.use_external_issue_tracker=Usar tracker externo de incidencias
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato URL del tracker de incidencias externo settings.tracker_url_format=Formato URL del tracker de incidencias externo
settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias: settings.tracker_issue_style=Estilo de etiquetado del tracker externo de incidencias:
settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.numeric=Numérico
@ -1037,7 +1040,7 @@ auths.delete_auth_title=Borrado de autenticación
auths.delete_auth_desc=Esta autenticación será eliminada. ¿Deseas continuar? auths.delete_auth_desc=Esta autenticación será eliminada. ¿Deseas continuar?
auths.still_in_used=Este método de autentificación aún es utilizado por algunos usuarios, por favor elimine o convierta estos usuarios a otro tipo de autentificación. auths.still_in_used=Este método de autentificación aún es utilizado por algunos usuarios, por favor elimine o convierta estos usuarios a otro tipo de autentificación.
auths.deletion_success=¡La autenticación ha sido eliminada con éxito! auths.deletion_success=¡La autenticación ha sido eliminada con éxito!
auths.login_source_exist=Login source '%s' already exists. auths.login_source_exist=El origen de autenticación '%s' ya existe.
config.server_config=Configuración del servidor config.server_config=Configuración del servidor
config.app_name=Nombre de la Aplicación config.app_name=Nombre de la Aplicación
@ -1048,6 +1051,7 @@ config.offline_mode=Modo Sin Conexión
config.disable_router_log=Deshabilitar Log del Router config.disable_router_log=Deshabilitar Log del Router
config.run_user=Ejecutada como Usuario config.run_user=Ejecutada como Usuario
config.run_mode=Modo de ejecución config.run_mode=Modo de ejecución
config.git_version=Git Version
config.repo_root_path=Ruta del Repositorio config.repo_root_path=Ruta del Repositorio
config.static_file_root_path=Ruta de los Ficheros Estáticos config.static_file_root_path=Ruta de los Ficheros Estáticos
config.log_file_root_path=Ruta de los Ficheros de Log config.log_file_root_path=Ruta de los Ficheros de Log

4
conf/locale/locale_fi-FI.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Julkaisu versiosi ei tue SQLite3, ole hyvä ja lataa viral
invalid_db_setting=Tietokanta asetus ei ole oikea: %v invalid_db_setting=Tietokanta asetus ei ole oikea: %v
invalid_repo_path=Repo juuri polku on virheellinen: %v invalid_repo_path=Repo juuri polku on virheellinen: %v
run_user_not_match=Suoritus käyttäjä ei ole nykyinen käyttäjä: %s -> %s run_user_not_match=Suoritus käyttäjä ei ole nykyinen käyttäjä: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Asetuksien tallennus epäonnistui: %v save_config_failed=Asetuksien tallennus epäonnistui: %v
invalid_admin_setting=Ylläpito tili asetus virheellinen: %v invalid_admin_setting=Ylläpito tili asetus virheellinen: %v
install_success=Tervetuloa! Olemme iloisia että valitsit Gogs, pidä hauskaa ja pidä huolta itsestäsi. install_success=Tervetuloa! Olemme iloisia että valitsit Gogs, pidä hauskaa ja pidä huolta itsestäsi.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Vierailijat uudelleenohjataan URL-osoitteeseen k
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Käytä ulkoista vikaseurantaa settings.use_external_issue_tracker=Käytä ulkoista vikaseurantaa
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Ulkoisen vikaseurannan URL muoto settings.tracker_url_format=Ulkoisen vikaseurannan URL muoto
settings.tracker_issue_style=External Issue Tracker Naming Style: settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric settings.tracker_issue_style.numeric=Numeric
@ -1048,6 +1051,7 @@ config.offline_mode=Offline-tila
config.disable_router_log=Poista käytöstä reitittimen loki config.disable_router_log=Poista käytöstä reitittimen loki
config.run_user=Suorita käyttäjänä config.run_user=Suorita käyttäjänä
config.run_mode=Suoritustila config.run_mode=Suoritustila
config.git_version=Git Version
config.repo_root_path=Repon juuren polku config.repo_root_path=Repon juuren polku
config.static_file_root_path=Staattisen tiedoston juuren polku config.static_file_root_path=Staattisen tiedoston juuren polku
config.log_file_root_path=Lokitiedoston juuren polku config.log_file_root_path=Lokitiedoston juuren polku

4
conf/locale/locale_fr-FR.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Votre version publiée ne prend pas en charge SQLite3. Veu
invalid_db_setting=Paramètres de base de données incorrects : %v invalid_db_setting=Paramètres de base de données incorrects : %v
invalid_repo_path=Chemin vers la racine du dépôt invalide : %v invalid_repo_path=Chemin vers la racine du dépôt invalide : %v
run_user_not_match=L'utilisateur d'exécution saisi n'est pas l'utilisateur d'exécution actuel : %s -> %s run_user_not_match=L'utilisateur d'exécution saisi n'est pas l'utilisateur d'exécution actuel : %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=La sauvegarde de la configuration a échoué : %v save_config_failed=La sauvegarde de la configuration a échoué : %v
invalid_admin_setting=Paramètres du compte administrateur invalides : %v invalid_admin_setting=Paramètres du compte administrateur invalides : %v
install_success=Bienvenue ! Nous sommes heureux que vous ayez choisi Gogs, amusez-vous et prenez soin de vous. install_success=Bienvenue ! Nous sommes heureux que vous ayez choisi Gogs, amusez-vous et prenez soin de vous.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Les visiteurs seront redirigés vers cette URL l
settings.issues_desc=Activer le système de tickets settings.issues_desc=Activer le système de tickets
settings.use_internal_issue_tracker=Utiliser le système simplifié de tickets interne settings.use_internal_issue_tracker=Utiliser le système simplifié de tickets interne
settings.use_external_issue_tracker=Utiliser un bug-tracker externe settings.use_external_issue_tracker=Utiliser un bug-tracker externe
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Format d'URL du bug tracker settings.tracker_url_format=Format d'URL du bug tracker
settings.tracker_issue_style=Style de nommage des bugs du tracker externe : settings.tracker_issue_style=Style de nommage des bugs du tracker externe :
settings.tracker_issue_style.numeric=Numérique settings.tracker_issue_style.numeric=Numérique
@ -1048,6 +1051,7 @@ config.offline_mode=Mode hors-ligne
config.disable_router_log=Désactiver la Journalisation du Routeur config.disable_router_log=Désactiver la Journalisation du Routeur
config.run_user=Utilisateur système config.run_user=Utilisateur système
config.run_mode=Mode d'Éxécution config.run_mode=Mode d'Éxécution
config.git_version=Git Version
config.repo_root_path=Emplacement des Dépôts config.repo_root_path=Emplacement des Dépôts
config.static_file_root_path=Chemin statique des fichiers racines config.static_file_root_path=Chemin statique des fichiers racines
config.log_file_root_path=Emplacement Racine du Fichier Journal config.log_file_root_path=Emplacement Racine du Fichier Journal

4
conf/locale/locale_gl-ES.ini

@ -116,6 +116,7 @@ sqlite3_not_available=A túa versión non soporta SQLite3, por favor, descarga o
invalid_db_setting=A configuración da base de datos non é correcta: %v invalid_db_setting=A configuración da base de datos non é correcta: %v
invalid_repo_path=A ruta da raíz do repositorio é inválida: %v invalid_repo_path=A ruta da raíz do repositorio é inválida: %v
run_user_not_match=A persoa usuaria que está executando a aplicación non é a persoa usuaria actual: %s -> %s run_user_not_match=A persoa usuaria que está executando a aplicación non é a persoa usuaria actual: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Erro ao gardar a configuración: %v save_config_failed=Erro ao gardar a configuración: %v
invalid_admin_setting=A configuración da conta de administración é inválida: %v invalid_admin_setting=A configuración da conta de administración é inválida: %v
install_success=Benvido/a! Estamos encantados de que escolleses Gogs, divírtete e cóidate. install_success=Benvido/a! Estamos encantados de que escolleses Gogs, divírtete e cóidate.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Os visitantes serán redireccionados á URL cand
settings.issues_desc=Habilitar rastrexo de incidencias settings.issues_desc=Habilitar rastrexo de incidencias
settings.use_internal_issue_tracker=Usar rastrexo de incidencias lixeiro incluído settings.use_internal_issue_tracker=Usar rastrexo de incidencias lixeiro incluído
settings.use_external_issue_tracker=Usar tracker externo de incidencias settings.use_external_issue_tracker=Usar tracker externo de incidencias
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato URL do tracker de incidencias externo settings.tracker_url_format=Formato URL do tracker de incidencias externo
settings.tracker_issue_style=Estilo de etiquetaxe do tracker externo de incidencias: settings.tracker_issue_style=Estilo de etiquetaxe do tracker externo de incidencias:
settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.numeric=Numérico
@ -1048,6 +1051,7 @@ config.offline_mode=Modo sen conexión
config.disable_router_log=Deshabilitar log do router config.disable_router_log=Deshabilitar log do router
config.run_user=Executada como usuario config.run_user=Executada como usuario
config.run_mode=Modo de execución config.run_mode=Modo de execución
config.git_version=Git Version
config.repo_root_path=Ruta do repositorio config.repo_root_path=Ruta do repositorio
config.static_file_root_path=Ruta dos ficheiros estáticos config.static_file_root_path=Ruta dos ficheiros estáticos
config.log_file_root_path=Ruta dos ficheiros de log config.log_file_root_path=Ruta dos ficheiros de log

4
conf/locale/locale_it-IT.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Questa versione non supporta SQLite3, si prega di scaricar
invalid_db_setting=La configurazione del database non è corretta: %v invalid_db_setting=La configurazione del database non è corretta: %v
invalid_repo_path=Percorso root del repository invalido: %v invalid_repo_path=Percorso root del repository invalido: %v
run_user_not_match=Run user non è l'utente corrente: %s -> %s run_user_not_match=Run user non è l'utente corrente: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Fallito il salvataggio della configurazione: %v save_config_failed=Fallito il salvataggio della configurazione: %v
invalid_admin_setting=Impostazioni account Admin non valide: %v invalid_admin_setting=Impostazioni account Admin non valide: %v
install_success=Benvenuto! Siamo felici che tu abbia scelto Gogs, buon divertimento. install_success=Benvenuto! Siamo felici che tu abbia scelto Gogs, buon divertimento.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=I visitatori verranno reindirizzati all'URL quan
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Utilizza gestore di problemi esterno settings.use_external_issue_tracker=Utilizza gestore di problemi esterno
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato URL Gestore Problemi Esterno settings.tracker_url_format=Formato URL Gestore Problemi Esterno
settings.tracker_issue_style=External Issue Tracker Naming Style: settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric settings.tracker_issue_style.numeric=Numeric
@ -1048,6 +1051,7 @@ config.offline_mode=Modalità Offline
config.disable_router_log=Disattivare Log del Router config.disable_router_log=Disattivare Log del Router
config.run_user=Utente Esecutore config.run_user=Utente Esecutore
config.run_mode=Modalità Esecuzione config.run_mode=Modalità Esecuzione
config.git_version=Git Version
config.repo_root_path=Percorso Root del Repository config.repo_root_path=Percorso Root del Repository
config.static_file_root_path=Percorso Root del File Statico config.static_file_root_path=Percorso Root del File Statico
config.log_file_root_path=Percorso Root del File di Log config.log_file_root_path=Percorso Root del File di Log

4
conf/locale/locale_ja-JP.ini

@ -116,6 +116,7 @@ sqlite3_not_available=このリリース バージョンは SQLite3 をサポー
invalid_db_setting=データベースの設定が正しくありません: %v invalid_db_setting=データベースの設定が正しくありません: %v
invalid_repo_path=リポジトリのルート パスが無効です: %v invalid_repo_path=リポジトリのルート パスが無効です: %v
run_user_not_match=実行ユーザーは、現在のユーザーではない: %s-> %s run_user_not_match=実行ユーザーは、現在のユーザーではない: %s-> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=構成の保存に失敗した: %v save_config_failed=構成の保存に失敗した: %v
invalid_admin_setting=管理者アカウントの設定が無効です: %v invalid_admin_setting=管理者アカウントの設定が無効です: %v
install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう! install_success=ようこそ!我々はあなたが Gogs を選んでくれて嬉しいです!楽しみましょう!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Visitors will be redirected to URL when they cli
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=外部課題トラッキングシステムを使用 settings.use_external_issue_tracker=外部課題トラッキングシステムを使用
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット settings.tracker_url_format=外部課題トラッキングツール URLのフォーマット
settings.tracker_issue_style=External Issue Tracker Naming Style: settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=数値 settings.tracker_issue_style.numeric=数値
@ -1048,6 +1051,7 @@ config.offline_mode=オフラインモード
config.disable_router_log=ルーターのログを無効にする config.disable_router_log=ルーターのログを無効にする
config.run_user=実行ユーザ config.run_user=実行ユーザ
config.run_mode=実行モード config.run_mode=実行モード
config.git_version=Git Version
config.repo_root_path=リポジトリのルートパス config.repo_root_path=リポジトリのルートパス
config.static_file_root_path=静的ファイルのルートパス config.static_file_root_path=静的ファイルのルートパス
config.log_file_root_path=ログ ファイルのルート パス config.log_file_root_path=ログ ファイルのルート パス

4
conf/locale/locale_ko-KR.ini

@ -116,6 +116,7 @@ sqlite3_not_available=설치하신 버전은 SQLite3을 지원하지 않으므
invalid_db_setting=데이터베이스 설정이 올바르지 않습니다: %v invalid_db_setting=데이터베이스 설정이 올바르지 않습니다: %v
invalid_repo_path=저장소 루트 경로가 올바르지 않습니다: %v invalid_repo_path=저장소 루트 경로가 올바르지 않습니다: %v
run_user_not_match=실행 유저가 현재 유저가 아닙니다: %s -> %s run_user_not_match=실행 유저가 현재 유저가 아닙니다: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=설정을 저장할 수 없습니다: %v save_config_failed=설정을 저장할 수 없습니다: %v
invalid_admin_setting=관리자 계정 설정이 잘못되었습니다: %v invalid_admin_setting=관리자 계정 설정이 잘못되었습니다: %v
install_success=환영합니다! Gogs를 선택해 주셔서 감사합니다. install_success=환영합니다! Gogs를 선택해 주셔서 감사합니다.
@ -657,6 +658,8 @@ settings.external_wiki_url_desc=탭을 클릭하면 URL로 리다이렉트됩니
settings.issues_desc=이슈 추적기를 사용하도록 설정 settings.issues_desc=이슈 추적기를 사용하도록 설정
settings.use_internal_issue_tracker=내장된 경량 이슈 트레커를 사용 settings.use_internal_issue_tracker=내장된 경량 이슈 트레커를 사용
settings.use_external_issue_tracker=외부 이슈 트래커 사용하기 settings.use_external_issue_tracker=외부 이슈 트래커 사용하기
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=외부 이슈 트래커 URL 형식 settings.tracker_url_format=외부 이슈 트래커 URL 형식
settings.tracker_issue_style=외부 이슈 트래커 명명 스타일: settings.tracker_issue_style=외부 이슈 트래커 명명 스타일:
settings.tracker_issue_style.numeric=숫자 settings.tracker_issue_style.numeric=숫자
@ -1049,6 +1052,7 @@ config.offline_mode=오프라인 모드
config.disable_router_log=라우터 로그 비활성화 config.disable_router_log=라우터 로그 비활성화
config.run_user=데몬 실행 계정 config.run_user=데몬 실행 계정
config.run_mode=실행 모드 config.run_mode=실행 모드
config.git_version=Git Version
config.repo_root_path=저장소 최상위 경로 config.repo_root_path=저장소 최상위 경로
config.static_file_root_path=정적 파일 최상위 경로 config.static_file_root_path=정적 파일 최상위 경로
config.log_file_root_path=로그 파일 최상위 경로 config.log_file_root_path=로그 파일 최상위 경로

4
conf/locale/locale_lv-LV.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Jūsu versija neatbalsta SQLite3, lūdzu lejupielādējiet
invalid_db_setting=Datu bāzes iestatījums nav pareizs: %v invalid_db_setting=Datu bāzes iestatījums nav pareizs: %v
invalid_repo_path=Repozitorija atrašanās vieta ir nekorekta: %v invalid_repo_path=Repozitorija atrašanās vieta ir nekorekta: %v
run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Neizdevās saglabāt konfigurāciju: %v save_config_failed=Neizdevās saglabāt konfigurāciju: %v
invalid_admin_setting=Nekorekts admin konta iestatījums: %v invalid_admin_setting=Nekorekts admin konta iestatījums: %v
install_success=Laipni lūdzam! Mēs priecājamies, ka Jūs izvēlaties Gogs, patīkamu lietošanu! install_success=Laipni lūdzam! Mēs priecājamies, ka Jūs izvēlaties Gogs, patīkamu lietošanu!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Apmeklētāji tiks novirzīti uz adresi, kad vi
settings.issues_desc=Iespējot problēmu sekotāju settings.issues_desc=Iespējot problēmu sekotāju
settings.use_internal_issue_tracker=Izmantot iebūvētu vieglu problēmu sekotāju settings.use_internal_issue_tracker=Izmantot iebūvētu vieglu problēmu sekotāju
settings.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju settings.use_external_issue_tracker=Izmantot ārējo problēmu sekotāju
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts settings.tracker_url_format=Ārējā problēmu sekotāja adreses formāts
settings.tracker_issue_style=Ārējā problēmu reģistra nosaukumu stils: settings.tracker_issue_style=Ārējā problēmu reģistra nosaukumu stils:
settings.tracker_issue_style.numeric=Cipari settings.tracker_issue_style.numeric=Cipari
@ -1048,6 +1051,7 @@ config.offline_mode=Bezsaistes režīms
config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu
config.run_user=Izpildes lietotājs config.run_user=Izpildes lietotājs
config.run_mode=Izpildes režīms config.run_mode=Izpildes režīms
config.git_version=Git Version
config.repo_root_path=Repozitoriju glabāšanas vieta config.repo_root_path=Repozitoriju glabāšanas vieta
config.static_file_root_path=Statisko failu atrašanās vieta config.static_file_root_path=Statisko failu atrašanās vieta
config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta

4
conf/locale/locale_nl-NL.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Uw versie biedt geen ondersteuning voor SQLite3, download
invalid_db_setting=Uw database instellingen zijn niet correct: %v invalid_db_setting=Uw database instellingen zijn niet correct: %v
invalid_repo_path=Repositorie basis map is niet correct: %v invalid_repo_path=Repositorie basis map is niet correct: %v
run_user_not_match=De uitvoerende gebruiker is niet de huidig gebruiker: %s -> %s run_user_not_match=De uitvoerende gebruiker is niet de huidig gebruiker: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Kan de configuratie niet opslaan: %v save_config_failed=Kan de configuratie niet opslaan: %v
invalid_admin_setting=Uw admin-instellingen zijn niet geldig: %v invalid_admin_setting=Uw admin-instellingen zijn niet geldig: %v
install_success=Welkom! Wij zijn veheugd dat u voor Gogs heeft gekozen, veel plezier en tot ziens install_success=Welkom! Wij zijn veheugd dat u voor Gogs heeft gekozen, veel plezier en tot ziens
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Bezoekers worden doorgestuurd naar de URL als ze
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Externe issuetracker gebruiken settings.use_external_issue_tracker=Externe issuetracker gebruiken
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=URL-formaat externe issuetracker settings.tracker_url_format=URL-formaat externe issuetracker
settings.tracker_issue_style=External Issue Tracker Naming Style: settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric settings.tracker_issue_style.numeric=Numeric
@ -1048,6 +1051,7 @@ config.offline_mode=Offline-modus
config.disable_router_log=Router-log uitschakelen config.disable_router_log=Router-log uitschakelen
config.run_user=Uitvoerende gebruiker config.run_user=Uitvoerende gebruiker
config.run_mode=Uitvoer modus config.run_mode=Uitvoer modus
config.git_version=Git Version
config.repo_root_path=Repositorie basis pad config.repo_root_path=Repositorie basis pad
config.static_file_root_path=Statische bestanden basis pad config.static_file_root_path=Statische bestanden basis pad
config.log_file_root_path=Log bestand basis pad config.log_file_root_path=Log bestand basis pad

4
conf/locale/locale_pl-PL.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Twoje wydanie nie obsługuje SQLite3, proszę pobrać ofic
invalid_db_setting=Ustawienia bazy danych nie są poprawne: %v invalid_db_setting=Ustawienia bazy danych nie są poprawne: %v
invalid_repo_path=Ścieżka repozytoriów nie jest poprawna: %v invalid_repo_path=Ścieżka repozytoriów nie jest poprawna: %v
run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -> %s run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Nie udało się zapisać konfiguracji: %v save_config_failed=Nie udało się zapisać konfiguracji: %v
invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
install_success=Cześć! Cieszymy się, że wybierałeś Gogs, baw się dobrze. install_success=Cześć! Cieszymy się, że wybierałeś Gogs, baw się dobrze.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Odwiedzający zostaną przekierowani do adresu U
settings.issues_desc=Włącz system zgłaszania problemów settings.issues_desc=Włącz system zgłaszania problemów
settings.use_internal_issue_tracker=Użyj wbudowany lekki system zgłaszania problemów settings.use_internal_issue_tracker=Użyj wbudowany lekki system zgłaszania problemów
settings.use_external_issue_tracker=Użyj zewnętrznego systemu zgłaszania problemów settings.use_external_issue_tracker=Użyj zewnętrznego systemu zgłaszania problemów
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu settings.tracker_url_format=Format dla adresu URL zewnętrznego systemu
settings.tracker_issue_style=Styl nazw zewnętrznego systemu zgłaszania problemów: settings.tracker_issue_style=Styl nazw zewnętrznego systemu zgłaszania problemów:
settings.tracker_issue_style.numeric=Numeryczny settings.tracker_issue_style.numeric=Numeryczny
@ -1048,6 +1051,7 @@ config.offline_mode=Tryb offline
config.disable_router_log=Wyłącz dziennik routera config.disable_router_log=Wyłącz dziennik routera
config.run_user=Użytkownik uruchomieniowy config.run_user=Użytkownik uruchomieniowy
config.run_mode=Tryb uruchamienia config.run_mode=Tryb uruchamienia
config.git_version=Git Version
config.repo_root_path=Ścieżka repozytoriów config.repo_root_path=Ścieżka repozytoriów
config.static_file_root_path=Ścieżka plików statycznych config.static_file_root_path=Ścieżka plików statycznych
config.log_file_root_path=Ścieżka plików dziennika config.log_file_root_path=Ścieżka plików dziennika

4
conf/locale/locale_pt-BR.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Sua versão não suporta SQLite3, por favor faça o downlo
invalid_db_setting=Configuração do banco de dados não está correta: %v invalid_db_setting=Configuração do banco de dados não está correta: %v
invalid_repo_path=A raiz do repositório é inválida: %v invalid_repo_path=A raiz do repositório é inválida: %v
run_user_not_match=O usuário da execução não é o usuário atual: %s -> %s run_user_not_match=O usuário da execução não é o usuário atual: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Falha ao salvar a configuração: %v save_config_failed=Falha ao salvar a configuração: %v
invalid_admin_setting=Configuração da conta de administrador está inválida: %v invalid_admin_setting=Configuração da conta de administrador está inválida: %v
install_success=Bem-vindo! Estamos contentes que você escolheu o Gogs, divirta-se e tenha cuidado. install_success=Bem-vindo! Estamos contentes que você escolheu o Gogs, divirta-se e tenha cuidado.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Os visitantes serão redirecionados para a URL a
settings.issues_desc=Habilitar issue tracker settings.issues_desc=Habilitar issue tracker
settings.use_internal_issue_tracker=Usar o issue tracker nativo settings.use_internal_issue_tracker=Usar o issue tracker nativo
settings.use_external_issue_tracker=Usar issue tracker externo settings.use_external_issue_tracker=Usar issue tracker externo
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Formato de URL do issue tracker externo settings.tracker_url_format=Formato de URL do issue tracker externo
settings.tracker_issue_style=Estilo de nome de issue tracker externo: settings.tracker_issue_style=Estilo de nome de issue tracker externo:
settings.tracker_issue_style.numeric=Numérico settings.tracker_issue_style.numeric=Numérico
@ -1048,6 +1051,7 @@ config.offline_mode=Modo Offline
config.disable_router_log=Desabilitar o Log do router config.disable_router_log=Desabilitar o Log do router
config.run_user=Usuário de execução config.run_user=Usuário de execução
config.run_mode=Modo de execução config.run_mode=Modo de execução
config.git_version=Git Version
config.repo_root_path=Caminho raiz do repositório config.repo_root_path=Caminho raiz do repositório
config.static_file_root_path=Caminho raiz para arquivo estático config.static_file_root_path=Caminho raiz para arquivo estático
config.log_file_root_path=Caminho raiz para arquivo de log config.log_file_root_path=Caminho raiz para arquivo de log

26
conf/locale/locale_ru-RU.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Ваша версия не поддерживает SQLite
invalid_db_setting=Настройки базы данных не правильные: %v invalid_db_setting=Настройки базы данных не правильные: %v
invalid_repo_path=Недопустимый путь к корню репозитория: %v invalid_repo_path=Недопустимый путь к корню репозитория: %v
run_user_not_match=Текущий пользователь не является пользователем для запуска: %s -> %s run_user_not_match=Текущий пользователь не является пользователем для запуска: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Не удалось сохранить конфигурацию: %v save_config_failed=Не удалось сохранить конфигурацию: %v
invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v
install_success=Добро пожаловать! Мы рады, что вы выбрали Gogs. Веселитесь и берегите себя. install_success=Добро пожаловать! Мы рады, что вы выбрали Gogs. Веселитесь и берегите себя.
@ -137,7 +138,7 @@ issues.in_your_repos=В ваших репозиториях
[explore] [explore]
repos=Репозитории repos=Репозитории
users=Пользователи users=Пользователи
organizations=Organizations organizations=Организации
search=Поиск search=Поиск
[auth] [auth]
@ -337,9 +338,9 @@ access_token_deletion=Удаление личного токена доступ
access_token_deletion_desc=Удаление этого персонального токена доступа приведет к удалению всех связанных прав доступа к приложению. Вы хотите продолжить? access_token_deletion_desc=Удаление этого персонального токена доступа приведет к удалению всех связанных прав доступа к приложению. Вы хотите продолжить?
delete_token_success=Персональный токен доступа успешно удален! Не забудьте изменить настройки вашего приложения. delete_token_success=Персональный токен доступа успешно удален! Не забудьте изменить настройки вашего приложения.
orgs.none=You are not a member of any organizations. orgs.none=Вы не состоите ни в одной организации.
orgs.leave_title=Leave an organization orgs.leave_title=Покинуть организацию
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue? orgs.leave_desc=Вы потеряете доступ ко всем репозиториям и командам, как только покинете организацию. Вы хотите продолжить?
delete_account=Удалить свой аккаунт delete_account=Удалить свой аккаунт
delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть! delete_prompt=Этим действием вы удалите свою учетную запись навсегда и <strong>НЕ СМОЖЕТЕ</strong> ее вернуть!
@ -388,7 +389,7 @@ migrate_type=Тип миграции
migrate_type_helper=Этот репозиторий будет <span class="text blue">зеркалом</span> migrate_type_helper=Этот репозиторий будет <span class="text blue">зеркалом</span>
migrate_repo=Перенос репозитория migrate_repo=Перенос репозитория
migrate.clone_address=Скопировать адрес migrate.clone_address=Скопировать адрес
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL. migrate.clone_address_desc=Это может быть HTTP/HTTPS/GIT URL-адрес.
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path. migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path.
migrate.permission_denied=У вас нет прав на импорт локальных репозиториев. migrate.permission_denied=У вас нет прав на импорт локальных репозиториев.
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой. migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
@ -414,7 +415,7 @@ create_new_repo_command=Создать новый репозиторий из к
push_exist_repo=Отправить существующий репозиторий из командной строки push_exist_repo=Отправить существующий репозиторий из командной строки
repo_is_empty=Этот репозиторий пуст, пожалуйста, возвращайтесь позже! repo_is_empty=Этот репозиторий пуст, пожалуйста, возвращайтесь позже!
files=Files files=Файлы
branch=Ветка branch=Ветка
tree=Дерево tree=Дерево
filter_branch_and_tag=Фильтр по ветке или тегу filter_branch_and_tag=Фильтр по ветке или тегу
@ -431,7 +432,7 @@ file_history=История
file_view_raw=Посмотреть исходник file_view_raw=Посмотреть исходник
file_permalink=Постоянная ссылка file_permalink=Постоянная ссылка
file_too_large=Этот файл слишком большой, поэтому он не может быть отображен file_too_large=Этот файл слишком большой, поэтому он не может быть отображен
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag. video_not_supported_in_browser=Ваш браузер не поддерживает HTML5 видео тэг.
editor.new_file=Новый файл editor.new_file=Новый файл
editor.upload_file=Загрузить файл editor.upload_file=Загрузить файл
@ -461,7 +462,7 @@ editor.cancel=Отмена
editor.filename_cannot_be_empty=Имя файла не может быть пустым. editor.filename_cannot_be_empty=Имя файла не может быть пустым.
editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории. editor.branch_already_exists=Ветка «%s» уже существует в этом репозитории.
editor.directory_is_a_file=Запись «%s» в пути на верх является файлом, а не каталогом этого репозитория. editor.directory_is_a_file=Запись «%s» в пути на верх является файлом, а не каталогом этого репозитория.
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor. editor.file_is_a_symlink=Файл '%s' является символической ссылкой, которая не может быть изменена через веб-редактор.
editor.filename_is_a_directory=Файл «%s» является каталогом в этом репозитории. editor.filename_is_a_directory=Файл «%s» является каталогом в этом репозитории.
editor.file_editing_no_longer_exists=Редактируемый вами файл «%s» больше не существует в репозитории. editor.file_editing_no_longer_exists=Редактируемый вами файл «%s» больше не существует в репозитории.
editor.file_changed_while_editing=Содержимое файла изменилось со времени начала редактирования. <a target="_blank" href="%s"> нажмите здесь,</a> чтобы увидеть, что было изменено, или <strong>нажмите кнопку commit снова</strong>, чтобы перезаписать эти изменения. editor.file_changed_while_editing=Содержимое файла изменилось со времени начала редактирования. <a target="_blank" href="%s"> нажмите здесь,</a> чтобы увидеть, что было изменено, или <strong>нажмите кнопку commit снова</strong>, чтобы перезаписать эти изменения.
@ -586,8 +587,8 @@ pulls.cannot_auto_merge_desc=Этот запрос на слияние не мо
pulls.cannot_auto_merge_helper=Пожалуйста, совершите слияние вручную для урегулирования конфликтов. pulls.cannot_auto_merge_helper=Пожалуйста, совершите слияние вручную для урегулирования конфликтов.
pulls.merge_pull_request=Слить пулл-реквест pulls.merge_pull_request=Слить пулл-реквест
pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния. ` pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния. `
pulls.delete_branch=Delete Branch pulls.delete_branch=Удалить ветку
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence. pulls.delete_branch_has_new_commits=Нельзя удалить ветку, так как она имеет новые коммиты после слияния.
milestones.new=Новая контрольная точка milestones.new=Новая контрольная точка
milestones.open_tab=%d открыты milestones.open_tab=%d открыты
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Посетители будут перенапр
settings.issues_desc=Включить систему отслеживания ошибок settings.issues_desc=Включить систему отслеживания ошибок
settings.use_internal_issue_tracker=Использовать встроенную легковесную систему отслеживания ошибок settings.use_internal_issue_tracker=Использовать встроенную легковесную систему отслеживания ошибок
settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок settings.use_external_issue_tracker=Использовать внешнюю систему отслеживания ошибок
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок. settings.tracker_url_format=Внешний формат ссылки системы отслеживания ошибок.
settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач: settings.tracker_issue_style=Стиль Именования Внешней Системы Учета Задач:
settings.tracker_issue_style.numeric=Цифровой settings.tracker_issue_style.numeric=Цифровой
@ -1037,7 +1040,7 @@ auths.delete_auth_title=Удаление канала аутентификаци
auths.delete_auth_desc=Этот канал аутентификации будет удален. Вы уверены что хотите продолжить? auths.delete_auth_desc=Этот канал аутентификации будет удален. Вы уверены что хотите продолжить?
auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему. auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему.
auths.deletion_success=Канал аутентификации успешно удален! auths.deletion_success=Канал аутентификации успешно удален!
auths.login_source_exist=Login source '%s' already exists. auths.login_source_exist=Источник входа '%s' уже существует.
config.server_config=Конфигурация сервера config.server_config=Конфигурация сервера
config.app_name=Имя приложения config.app_name=Имя приложения
@ -1048,6 +1051,7 @@ config.offline_mode=Автономный режим
config.disable_router_log=Отключение журнала маршрутизатора config.disable_router_log=Отключение журнала маршрутизатора
config.run_user=Запуск пользователем config.run_user=Запуск пользователем
config.run_mode=Режим выполнения config.run_mode=Режим выполнения
config.git_version=Git Version
config.repo_root_path=Путь до корня репозитория config.repo_root_path=Путь до корня репозитория
config.static_file_root_path=Статичный путь до файла config.static_file_root_path=Статичный путь до файла
config.log_file_root_path=Путь до папки с логами config.log_file_root_path=Путь до папки с логами

4
conf/locale/locale_sr-SP.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Ваша верзија не подржава SQLite3, м
invalid_db_setting=Подешавања базе података су неправилна: %v invalid_db_setting=Подешавања базе података су неправилна: %v
invalid_repo_path=Пут до корена спремишта не неправилно: %v invalid_repo_path=Пут до корена спремишта не неправилно: %v
run_user_not_match=Тренутни корисник није корисник за покретање: %s -> %s run_user_not_match=Тренутни корисник није корисник за покретање: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Није могуће сачувати конфигурацију: %v save_config_failed=Није могуће сачувати конфигурацију: %v
invalid_admin_setting=Подешавањна администратора су неправилна: %v invalid_admin_setting=Подешавањна администратора су неправилна: %v
install_success=Добродошли! Ми смо срећни што сте изабрали Gogs. install_success=Добродошли! Ми смо срећни што сте изабрали Gogs.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Посетиоци ће бити преусме
settings.issues_desc=Омогући систем праћења грешака settings.issues_desc=Омогући систем праћења грешака
settings.use_internal_issue_tracker=Користи уграђен систем праћења грешака settings.use_internal_issue_tracker=Користи уграђен систем праћења грешака
settings.use_external_issue_tracker=Користи спољни систем праћења грешака settings.use_external_issue_tracker=Користи спољни систем праћења грешака
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Спољни формат везе система за праћење грешака settings.tracker_url_format=Спољни формат везе система за праћење грешака
settings.tracker_issue_style=Стил именовања на спољном систему: settings.tracker_issue_style=Стил именовања на спољном систему:
settings.tracker_issue_style.numeric=Нумерично settings.tracker_issue_style.numeric=Нумерично
@ -1048,6 +1051,7 @@ config.offline_mode=Режим ван мреже
config.disable_router_log=Онемогући журнал рутера config.disable_router_log=Онемогући журнал рутера
config.run_user=Покретни корисник config.run_user=Покретни корисник
config.run_mode=Режим извршавања config.run_mode=Режим извршавања
config.git_version=Git Version
config.repo_root_path=Пут до корена спремишта config.repo_root_path=Пут до корена спремишта
config.static_file_root_path=Пут до статичке датотеке config.static_file_root_path=Пут до статичке датотеке
config.log_file_root_path=Пут до журнала config.log_file_root_path=Пут до журнала

4
conf/locale/locale_sv-SE.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Din release stödjer ej SQLite3, ladda vänligen ner den o
invalid_db_setting=Databas inställningen är inkorrekt: %v invalid_db_setting=Databas inställningen är inkorrekt: %v
invalid_repo_path=Utvecklingskatalogens rotsökväg är ogiltig: %v invalid_repo_path=Utvecklingskatalogens rotsökväg är ogiltig: %v
run_user_not_match=Köranvändaren är inte aktuell användare: %s -> %s run_user_not_match=Köranvändaren är inte aktuell användare: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Konfigurationssparningen misslyckades: %v save_config_failed=Konfigurationssparningen misslyckades: %v
invalid_admin_setting=Inställningarna för administratörskontot är felaktiga: %v invalid_admin_setting=Inställningarna för administratörskontot är felaktiga: %v
install_success=Välkommen! Vi är glada att du väljer Gogs, ha kul och ta hand om dig. install_success=Välkommen! Vi är glada att du väljer Gogs, ha kul och ta hand om dig.
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Besökare kommer att bli omdirigerade till denna
settings.issues_desc=Aktivera ärendehantering settings.issues_desc=Aktivera ärendehantering
settings.use_internal_issue_tracker=Använd enkel inbyggd ärendehantering settings.use_internal_issue_tracker=Använd enkel inbyggd ärendehantering
settings.use_external_issue_tracker=Använd extern ärendehanterare settings.use_external_issue_tracker=Använd extern ärendehanterare
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=URL-Format För Extern Ärendehanterare settings.tracker_url_format=URL-Format För Extern Ärendehanterare
settings.tracker_issue_style=Namngivningsstil hos det externa ärendehanteringsystemet: settings.tracker_issue_style=Namngivningsstil hos det externa ärendehanteringsystemet:
settings.tracker_issue_style.numeric=Numerisk settings.tracker_issue_style.numeric=Numerisk
@ -1048,6 +1051,7 @@ config.offline_mode=Offline Mode
config.disable_router_log=Disable Router Log config.disable_router_log=Disable Router Log
config.run_user=Run User config.run_user=Run User
config.run_mode=Run Mode config.run_mode=Run Mode
config.git_version=Git Version
config.repo_root_path=Rotsökväg för utvecklingskatalog config.repo_root_path=Rotsökväg för utvecklingskatalog
config.static_file_root_path=Static File Root Path config.static_file_root_path=Static File Root Path
config.log_file_root_path=Log File Root Path config.log_file_root_path=Log File Root Path

4
conf/locale/locale_tr-TR.ini

@ -116,6 +116,7 @@ sqlite3_not_available=Yayın sürümünüz SQLite3'ü desteklemiyor, lütfen %s'
invalid_db_setting=Veritabanı ayarları geçersiz: %v invalid_db_setting=Veritabanı ayarları geçersiz: %v
invalid_repo_path=Depo kök dizini geçersiz: %v invalid_repo_path=Depo kök dizini geçersiz: %v
run_user_not_match=Çalıştırma kullanıcısı geçerli kullanıcı değil: %s -> %s run_user_not_match=Çalıştırma kullanıcısı geçerli kullanıcı değil: %s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=Yapılandırma kaydedilemedi: %v save_config_failed=Yapılandırma kaydedilemedi: %v
invalid_admin_setting=Yönetici hesap ayarları geçersiz: %v invalid_admin_setting=Yönetici hesap ayarları geçersiz: %v
install_success=Merhaba! Gogs'u tercih ettiğiniz için çok mutluyuz, keyfini çıkarın! install_success=Merhaba! Gogs'u tercih ettiğiniz için çok mutluyuz, keyfini çıkarın!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=Ziyaretçiler, sekmeye tıkladıklarında bağla
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=Harici sorun takipçisi kullan settings.use_external_issue_tracker=Harici sorun takipçisi kullan
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı
settings.tracker_issue_style=Harici Hata İzleyicisi Adlandırma Stili: settings.tracker_issue_style=Harici Hata İzleyicisi Adlandırma Stili:
settings.tracker_issue_style.numeric=Sayısal settings.tracker_issue_style.numeric=Sayısal
@ -1048,6 +1051,7 @@ config.offline_mode=Çevrim Dışı Modu
config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak
config.run_user=Çalıştırma Kullanıcısı config.run_user=Çalıştırma Kullanıcısı
config.run_mode=Çalıştırma Modu config.run_mode=Çalıştırma Modu
config.git_version=Git Version
config.repo_root_path=Depo Kök Yolu config.repo_root_path=Depo Kök Yolu
config.static_file_root_path=Sabit Dosya Kök Yolu config.static_file_root_path=Sabit Dosya Kök Yolu
config.log_file_root_path=Log Dosyası Kök Yolu config.log_file_root_path=Log Dosyası Kök Yolu

4
conf/locale/locale_zh-CN.ini

@ -116,6 +116,7 @@ sqlite3_not_available=您所使用的发行版不支持 SQLite3,请从 %s 下
invalid_db_setting=数据库设置不正确:%v invalid_db_setting=数据库设置不正确:%v
invalid_repo_path=仓库根目录设置不正确:%v invalid_repo_path=仓库根目录设置不正确:%v
run_user_not_match=运行系统用户非当前用户:%s -> %s run_user_not_match=运行系统用户非当前用户:%s -> %s
invalid_smtp_from=SMTP From 字段不合法:%v
save_config_failed=应用配置保存失败:%v save_config_failed=应用配置保存失败:%v
invalid_admin_setting=管理员帐户设置不正确:%v invalid_admin_setting=管理员帐户设置不正确:%v
install_success=您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG! install_success=您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=当访问者单击分页标签时,将会被重
settings.issues_desc=启用工单管理系统 settings.issues_desc=启用工单管理系统
settings.use_internal_issue_tracker=使用内置的轻量级工单管理系统 settings.use_internal_issue_tracker=使用内置的轻量级工单管理系统
settings.use_external_issue_tracker=使用外部的工单管理系统 settings.use_external_issue_tracker=使用外部的工单管理系统
settings.external_tracker_url=外部工单管理系统 URL
settings.external_tracker_url_desc=当访问者单击分页标签时,将会被重定向到该链接。
settings.tracker_url_format=外部工单管理系统的 URL 格式 settings.tracker_url_format=外部工单管理系统的 URL 格式
settings.tracker_issue_style=外部工单管理系统命名风格: settings.tracker_issue_style=外部工单管理系统命名风格:
settings.tracker_issue_style.numeric=纯数字形式 settings.tracker_issue_style.numeric=纯数字形式
@ -1048,6 +1051,7 @@ config.offline_mode=离线模式
config.disable_router_log=关闭路由日志 config.disable_router_log=关闭路由日志
config.run_user=运行用户 config.run_user=运行用户
config.run_mode=运行模式 config.run_mode=运行模式
config.git_version=Git 版本
config.repo_root_path=仓库根目录 config.repo_root_path=仓库根目录
config.static_file_root_path=静态文件根目录 config.static_file_root_path=静态文件根目录
config.log_file_root_path=日志文件根目录 config.log_file_root_path=日志文件根目录

4
conf/locale/locale_zh-HK.ini

@ -116,6 +116,7 @@ sqlite3_not_available=您所使用的發行版本不支持 SQLite3,請從 %s
invalid_db_setting=數據庫設置不正確:%v invalid_db_setting=數據庫設置不正確:%v
invalid_repo_path=倉庫根目錄設置不正確:%v invalid_repo_path=倉庫根目錄設置不正確:%v
run_user_not_match=執行系統用戶非當前用戶:%s -> %s run_user_not_match=執行系統用戶非當前用戶:%s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=應用配置保存失敗:%v save_config_failed=應用配置保存失敗:%v
invalid_admin_setting=管理員帳戶設置不正確:%v invalid_admin_setting=管理員帳戶設置不正確:%v
install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG! install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG!
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到
settings.issues_desc=Enable issue tracker settings.issues_desc=Enable issue tracker
settings.use_internal_issue_tracker=Use builtin lightweight issue tracker settings.use_internal_issue_tracker=Use builtin lightweight issue tracker
settings.use_external_issue_tracker=使用外部的問題管理系統 settings.use_external_issue_tracker=使用外部的問題管理系統
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部問題管理系統的 URL 格式 settings.tracker_url_format=外部問題管理系統的 URL 格式
settings.tracker_issue_style=External Issue Tracker Naming Style: settings.tracker_issue_style=External Issue Tracker Naming Style:
settings.tracker_issue_style.numeric=Numeric settings.tracker_issue_style.numeric=Numeric
@ -1048,6 +1051,7 @@ config.offline_mode=離線模式
config.disable_router_log=關閉路由日志 config.disable_router_log=關閉路由日志
config.run_user=執行用戶 config.run_user=執行用戶
config.run_mode=執行模式 config.run_mode=執行模式
config.git_version=Git Version
config.repo_root_path=倉庫根目錄 config.repo_root_path=倉庫根目錄
config.static_file_root_path=靜態文件根目錄 config.static_file_root_path=靜態文件根目錄
config.log_file_root_path=日志文件根目錄 config.log_file_root_path=日志文件根目錄

28
conf/locale/locale_zh-TW.ini

@ -116,6 +116,7 @@ sqlite3_not_available=您所使用的發行版本不支持 SQLite3,請從 %s
invalid_db_setting=數據庫設置不正確:%v invalid_db_setting=數據庫設置不正確:%v
invalid_repo_path=倉庫根目錄設置不正確:%v invalid_repo_path=倉庫根目錄設置不正確:%v
run_user_not_match=執行系統用戶非當前用戶:%s -> %s run_user_not_match=執行系統用戶非當前用戶:%s -> %s
invalid_smtp_from=SMTP From field is not valid: %v
save_config_failed=應用配置保存失敗:%v save_config_failed=應用配置保存失敗:%v
invalid_admin_setting=管理員帳戶設置不正確:%v invalid_admin_setting=管理員帳戶設置不正確:%v
install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG! install_success=您好!我們很高興您選擇使用 Gogs,祝您使用愉快,代碼從此無 BUG!
@ -137,7 +138,7 @@ issues.in_your_repos=屬於該用戶倉庫的
[explore] [explore]
repos=探索倉庫 repos=探索倉庫
users=用戶 users=用戶
organizations=Organizations organizations=組織
search=搜索 search=搜索
[auth] [auth]
@ -337,9 +338,9 @@ access_token_deletion=刪除個人的連接token
access_token_deletion_desc=刪除此連接token將會刪除與相關應用程式的連結。您想要繼續嗎? access_token_deletion_desc=刪除此連接token將會刪除與相關應用程式的連結。您想要繼續嗎?
delete_token_success=您的連接token已成功刪除。請記得更新您的應用程式。 delete_token_success=您的連接token已成功刪除。請記得更新您的應用程式。
orgs.none=You are not a member of any organizations. orgs.none=您現在還不是任何組織的成員。
orgs.leave_title=Leave an organization orgs.leave_title=離開組織
orgs.leave_desc=You will lose access to all repositories and teams after you left the organization. Do you want to continue? orgs.leave_desc=離開組織後,所有與組織相關的倉庫和團隊權限將被取消。是否繼續?
delete_account=刪除當前帳戶 delete_account=刪除當前帳戶
delete_prompt=刪除操作會永久清除您的帳戶信息,並且 <strong>不可恢復</strong>! delete_prompt=刪除操作會永久清除您的帳戶信息,並且 <strong>不可恢復</strong>!
@ -388,8 +389,8 @@ migrate_type=遷移類型
migrate_type_helper=該倉庫將是一個 <span class="text blue">鏡像</span> migrate_type_helper=該倉庫將是一個 <span class="text blue">鏡像</span>
migrate_repo=遷移倉庫 migrate_repo=遷移倉庫
migrate.clone_address=複製地址 migrate.clone_address=複製地址
migrate.clone_address_desc=This can be a HTTP/HTTPS/GIT URL. migrate.clone_address_desc=該地址可以是 HTTP/HTTPS/GIT 類型的 URL。
migrate.clone_address_desc_import_local=You're also allowed to migrate a repository by local server path. migrate.clone_address_desc_import_local=您還可以用本地服務器路徑來遷移倉庫。
migrate.permission_denied=您並沒有導入本地倉庫的權限。 migrate.permission_denied=您並沒有導入本地倉庫的權限。
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄! migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
migrate.failed=遷移失敗:%v migrate.failed=遷移失敗:%v
@ -414,7 +415,7 @@ create_new_repo_command=從命令行創建一個新的倉庫
push_exist_repo=從命令行推送已經創建的倉庫 push_exist_repo=從命令行推送已經創建的倉庫
repo_is_empty=這倉庫不包含任何內容,請稍後再訪問! repo_is_empty=這倉庫不包含任何內容,請稍後再訪問!
files=Files files=檔案
branch=分支 branch=分支
tree=目錄樹 tree=目錄樹
filter_branch_and_tag=過濾分支或標籤 filter_branch_and_tag=過濾分支或標籤
@ -431,7 +432,7 @@ file_history=文件歷史
file_view_raw=查看原始文件 file_view_raw=查看原始文件
file_permalink=永久連結 file_permalink=永久連結
file_too_large=檔案太大,無法顯示 file_too_large=檔案太大,無法顯示
video_not_supported_in_browser=Your browser doesn't support HTML5 video tag. video_not_supported_in_browser=您的瀏覽器不支援 HTML5 影片播放標籤。
editor.new_file=開新檔案 editor.new_file=開新檔案
editor.upload_file=上傳檔案 editor.upload_file=上傳檔案
@ -461,7 +462,7 @@ editor.cancel=取消
editor.filename_cannot_be_empty=檔案名不能為空。 editor.filename_cannot_be_empty=檔案名不能為空。
editor.branch_already_exists='%s' 已存在於此存儲庫。 editor.branch_already_exists='%s' 已存在於此存儲庫。
editor.directory_is_a_file='%s' 在此倉庫中的路徑是檔案而不是目錄。 editor.directory_is_a_file='%s' 在此倉庫中的路徑是檔案而不是目錄。
editor.file_is_a_symlink=The file '%s' is a symlink that cannot be modified from the web editor. editor.file_is_a_symlink=檔案 '%s' 是一個符號連結,不能從 web 編輯器修改。
editor.filename_is_a_directory=檔案名 '%s' 是此資料庫中的現有目錄。 editor.filename_is_a_directory=檔案名 '%s' 是此資料庫中的現有目錄。
editor.file_editing_no_longer_exists=檔 '%s' 您正在編輯不再存在於資料庫。 editor.file_editing_no_longer_exists=檔 '%s' 您正在編輯不再存在於資料庫。
editor.file_changed_while_editing=從您開始編輯已更改檔的內容。<a target="_blank"href="%s"> 按一下此處</a> 以查看什麼發生了更改或 <strong>按提交再</strong> 覆蓋這些更改。 editor.file_changed_while_editing=從您開始編輯已更改檔的內容。<a target="_blank"href="%s"> 按一下此處</a> 以查看什麼發生了更改或 <strong>按提交再</strong> 覆蓋這些更改。
@ -586,8 +587,8 @@ pulls.cannot_auto_merge_desc=由於存在衝突,不能自動合併這推送請
pulls.cannot_auto_merge_helper=請手動合併來解決衝突。 pulls.cannot_auto_merge_helper=請手動合併來解決衝突。
pulls.merge_pull_request=合併請求 pulls.merge_pull_request=合併請求
pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d),您無法執行重新開啟操作。` pulls.open_unmerged_pull_exists=`由於已經存在來自相同倉庫和合併信息的未合併請求(#%d),您無法執行重新開啟操作。`
pulls.delete_branch=Delete Branch pulls.delete_branch=刪除分支
pulls.delete_branch_has_new_commits=Branch cannot be deleted because it has new commits after mergence. pulls.delete_branch_has_new_commits=該分支在合併完成後又推送了新的提交,無法執行刪除。
milestones.new=新的里程碑 milestones.new=新的里程碑
milestones.open_tab=%d 開啟中 milestones.open_tab=%d 開啟中
@ -656,6 +657,8 @@ settings.external_wiki_url_desc=當分頁上按一下,訪客將會重新導到
settings.issues_desc=啟用問題追蹤 settings.issues_desc=啟用問題追蹤
settings.use_internal_issue_tracker=使用內建輕量級問題追蹤 settings.use_internal_issue_tracker=使用內建輕量級問題追蹤
settings.use_external_issue_tracker=使用外部的問題管理系統 settings.use_external_issue_tracker=使用外部的問題管理系統
settings.external_tracker_url=External Issue Tracker URL
settings.external_tracker_url_desc=Visitors will be redirected to URL when they click on the tab.
settings.tracker_url_format=外部問題管理系統的 URL 格式 settings.tracker_url_format=外部問題管理系統的 URL 格式
settings.tracker_issue_style=外部公單管理系統命名風格: settings.tracker_issue_style=外部公單管理系統命名風格:
settings.tracker_issue_style.numeric=數字 settings.tracker_issue_style.numeric=數字
@ -1037,7 +1040,7 @@ auths.delete_auth_title=刪除認證操作
auths.delete_auth_desc=該認證將被刪除。是否繼續? auths.delete_auth_desc=該認證將被刪除。是否繼續?
auths.still_in_used=一些使用者仍然使用此驗證方式,請先刪除或轉換這些使用者到其它登入類型。 auths.still_in_used=一些使用者仍然使用此驗證方式,請先刪除或轉換這些使用者到其它登入類型。
auths.deletion_success=認證源刪除成功! auths.deletion_success=認證源刪除成功!
auths.login_source_exist=Login source '%s' already exists. auths.login_source_exist=登錄源 '%s' 已存在。
config.server_config=服務器配置 config.server_config=服務器配置
config.app_name=應用名稱 config.app_name=應用名稱
@ -1048,6 +1051,7 @@ config.offline_mode=離線模式
config.disable_router_log=關閉路由日志 config.disable_router_log=關閉路由日志
config.run_user=執行用戶 config.run_user=執行用戶
config.run_mode=執行模式 config.run_mode=執行模式
config.git_version=Git Version
config.repo_root_path=倉庫根目錄 config.repo_root_path=倉庫根目錄
config.static_file_root_path=靜態文件根目錄 config.static_file_root_path=靜態文件根目錄
config.log_file_root_path=日志文件根目錄 config.log_file_root_path=日志文件根目錄

14
docker/build.sh

@ -10,23 +10,15 @@ export GO15VENDOREXPERIMENT=1
# Install build deps # Install build deps
apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev go apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev go
# Install glide
git clone -b 0.10.2 https://github.com/Masterminds/glide ${GOPATH}/src/github.com/Masterminds/glide
cd ${GOPATH}/src/github.com/Masterminds/glide
make build
go install
# Build Gogs # Build Gogs
mkdir -p ${GOPATH}/src/github.com/gogits/ mkdir -p ${GOPATH}/src/github.com/gogits/
ln -s /app/gogs/ ${GOPATH}/src/github.com/gogits/gogs ln -s /app/gogs/ ${GOPATH}/src/github.com/gogits/gogs
cd ${GOPATH}/src/github.com/gogits/gogs cd ${GOPATH}/src/github.com/gogits/gogs
glide install go get -v -tags "sqlite cert pam" ./...
make build TAGS="sqlite cert pam" make build TAGS="sqlite cert pam"
# Cleanup GOPATH & vendoring dir # Cleanup GOPATH
rm -r $GOPATH /app/gogs/vendor rm -r $GOPATH
# Remove build deps # Remove build deps
apk --no-progress del build-deps apk --no-progress del build-deps

154
glide.lock generated

@ -1,154 +0,0 @@
hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
updated: 2016-06-12T17:35:14.27036884+08:00
imports:
- name: github.com/bradfitz/gomemcache
version: 2fafb84a66c4911e11a8f50955b01e74fe3ab9c5
subpackages:
- memcache
- name: github.com/urfave/cli
version: 347a9884a87374d000eec7e6445a34487c1f4a2b
- name: github.com/go-macaron/binding
version: 48920167fa152d02f228cfbece7e0f1e452d200a
- name: github.com/go-macaron/cache
version: 56173531277692bc2925924d51fda1cd0a6b8178
subpackages:
- memcache
- redis
- name: github.com/go-macaron/captcha
version: 8aa5919789ab301e865595eb4b1114d6b9847deb
- name: github.com/go-macaron/csrf
version: 6a9a7df172cc1fcd81e4585f44b09200b6087cc0
- name: github.com/go-macaron/gzip
version: cad1c6580a07c56f5f6bc52d66002a05985c5854
- name: github.com/go-macaron/i18n
version: ef57533c3b0fc2d8581deda14937e52f11a203ab
- name: github.com/go-macaron/inject
version: d8a0b8677191f4380287cfebd08e462217bac7ad
- name: github.com/go-macaron/session
version: 66031fcb37a0fff002a1f028eb0b3a815c78306b
subpackages:
- redis
- name: github.com/go-macaron/toolbox
version: 82b511550b0aefc36b3a28062ad3a52e812bee38
- name: github.com/go-sql-driver/mysql
version: 2e00b5cd70399450106cec6431c2e2ce3cae5034
- name: github.com/go-xorm/builder
version: 867edcc549127f15667ece8876c3a60093c9634b
- name: github.com/go-xorm/core
version: 2fbe2c76c6781d9e1c0398fc25386426e611f975
- name: github.com/go-xorm/xorm
version: 445a934d32ed0934aedf0ef99b4b7c69b22f8e58
- name: github.com/gogits/chardet
version: 2404f777256163ea3eadb273dada5dcb037993c0
- name: github.com/gogits/cron
version: 2fc07a4c4f1e3c4d2301c5ed578d5e2c31c70421
- name: github.com/gogits/git-module
version: 172cbc21accbf0085a58fd0832f46a9f694130e8
- name: github.com/gogits/go-gogs-client
version: 98046bb98061fc6baa5bb86359af0b7c300d384a
- name: github.com/gogits/go-libravatar
version: cd1abbd55d09b793672732a7a1dfdaa12a40dfd0
- name: github.com/issue9/identicon
version: d36b54562f4cf70c83653e13dc95c220c79ef521
- name: github.com/jaytaylor/html2text
version: d16d4129aab4e6be4497f4db898965f09b93b565
- name: github.com/kardianos/minwinsvc
version: cad6b2b879b0970e4245a20ebf1a81a756e2bb70
- name: github.com/klauspost/compress
version: 461e8fd8397ae84a23f56e385801e4feda2048ce
subpackages:
- gzip
- flate
- name: github.com/klauspost/cpuid
version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
- name: github.com/klauspost/crc32
version: cb6bfca970f6908083f26f39a79009d608efd5cd
- name: github.com/lib/pq
version: 67c3f2a8884c9b1aac5503c8d42ae4f73a93511c
subpackages:
- oid
- name: github.com/mattn/go-sqlite3
version: ce9149a3c941c30de51a01dbc5bc414ddaa52927
- name: github.com/mcuadros/go-version
version: 257f7b9a7d87427c8d7f89469a5958d57f8abd7c
- name: github.com/microcosm-cc/bluemonday
version: e79763773ab6222ca1d5a7cbd9d62d83c1f77081
- name: github.com/msteinert/pam
version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
- name: github.com/nfnt/resize
version: 891127d8d1b52734debe1b3c3d7e747502b6c366
- name: github.com/russross/blackfriday
version: 5f33e7b7878355cd2b7e6b8eefc48a5472c69f70
- name: github.com/satori/go.uuid
version: b061729afc07e77a8aa4fad0a2fd840958f1942a
- name: github.com/sergi/go-diff
version: 24e2351369ec4949b2ed0dc5c477afdd4c4034e8
subpackages:
- diffmatchpatch
- name: github.com/shurcooL/sanitized_anchor_name
version: 1dba4b3954bc059efc3991ec364f9f9a35f597d2
- name: github.com/Unknwon/cae
version: c6aac99ea2cae2ebaf23f26f76b04fe3fcfc9f8c
subpackages:
- zip
- name: github.com/Unknwon/com
version: 28b053d5a2923b87ce8c5a08f3af779894a72758
- name: github.com/Unknwon/i18n
version: 39d6f2727e0698b1021ceb6a77c1801aa92e7d5d
- name: github.com/Unknwon/paginater
version: 701c23f468663c34d1b1768c3ae1bcc57e11c5b3
- name: golang.org/x/crypto
version: dc137beb6cce2043eb6b5f223ab8bf51c32459f4
subpackages:
- ssh
- curve25519
- ed25519
- ed25519/internal/edwards25519
- name: golang.org/x/net
version: f2499483f923065a842d38eb4c7f1927e6fc6e6d
subpackages:
- html
- html/charset
- html/atom
- name: golang.org/x/sys
version: d75a52659825e75fff6158388dddc6a5b04f9ba5
subpackages:
- windows/svc
- windows
- name: golang.org/x/text
version: ece019dcfd29abcf65d0d1dfe145e8faad097640
subpackages:
- transform
- language
- encoding
- encoding/charmap
- encoding/htmlindex
- internal/tag
- encoding/internal/identifier
- encoding/internal
- encoding/japanese
- encoding/korean
- encoding/simplifiedchinese
- encoding/traditionalchinese
- encoding/unicode
- internal/utf8internal
- runes
- name: gopkg.in/alexcesaro/quotedprintable.v3
version: 2caba252f4dc53eaf6b553000885530023f54623
- name: gopkg.in/asn1-ber.v1
version: 4e86f4367175e39f69d9358a5f17b4dda270378d
- name: gopkg.in/bufio.v1
version: 567b2bfa514e796916c4747494d6ff5132a1dfce
- name: gopkg.in/editorconfig/editorconfig-core-go.v1
version: a872f05c2e34b37b567401384d202aff11ba06d4
- name: gopkg.in/gomail.v2
version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
- name: gopkg.in/ini.v1
version: e3c2d47c61e5333f9aa2974695dd94396eb69c75
- name: gopkg.in/ldap.v2
version: 8168ee085ee43257585e50c6441aadf54ecb2c9f
- name: gopkg.in/macaron.v1
version: 78521e4647ad5dcbabd5734d94582ca2373cbad8
- name: gopkg.in/redis.v2
version: e6179049628164864e6e84e973cfb56335748dea
devImports: []

59
glide.yaml

@ -1,59 +0,0 @@
package: github.com/gogits/gogs
import:
- package: github.com/Unknwon/cae
subpackages:
- zip
- package: github.com/Unknwon/com
- package: github.com/Unknwon/i18n
- package: github.com/Unknwon/paginater
- package: github.com/urfave/cli
- package: github.com/go-macaron/binding
- package: github.com/go-macaron/cache
subpackages:
- memcache
- redis
- package: github.com/go-macaron/captcha
- package: github.com/go-macaron/csrf
- package: github.com/go-macaron/gzip
- package: github.com/go-macaron/i18n
- package: github.com/go-macaron/session
subpackages:
- redis
- package: github.com/go-macaron/toolbox
- package: github.com/go-sql-driver/mysql
- package: github.com/go-xorm/core
- package: github.com/go-xorm/xorm
- package: github.com/gogits/chardet
- package: github.com/gogits/cron
- package: github.com/gogits/git-module
- package: github.com/gogits/go-gogs-client
- package: github.com/issue9/identicon
- package: github.com/kardianos/minwinsvc
- package: github.com/lib/pq
- package: github.com/mattn/go-sqlite3
- package: github.com/mcuadros/go-version
- package: github.com/microcosm-cc/bluemonday
- package: github.com/msteinert/pam
- package: github.com/nfnt/resize
- package: github.com/russross/blackfriday
- package: github.com/satori/go.uuid
- package: github.com/sergi/go-diff
subpackages:
- diffmatchpatch
- package: github.com/strk/go-libravatar
- package: golang.org/x/crypto
subpackages:
- ssh
- package: golang.org/x/net
subpackages:
- html
- html/charset
- package: golang.org/x/text
subpackages:
- transform
- language
- package: gopkg.in/editorconfig/editorconfig-core-go.v1
- package: gopkg.in/gomail.v2
- package: gopkg.in/ini.v1
- package: gopkg.in/ldap.v2
- package: gopkg.in/macaron.v1

6
gogs.go

@ -16,7 +16,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.9.131.0201" const APP_VER = "0.9.147.0214"
func init() { func init() {
setting.AppVer = APP_VER setting.AppVer = APP_VER
@ -29,8 +29,8 @@ func main() {
app.Version = APP_VER app.Version = APP_VER
app.Commands = []cli.Command{ app.Commands = []cli.Command{
cmd.CmdWeb, cmd.CmdWeb,
cmd.CmdServ, cmd.Serv,
cmd.CmdUpdate, cmd.CmdHook,
cmd.CmdDump, cmd.CmdDump,
cmd.CmdCert, cmd.CmdCert,
cmd.CmdAdmin, cmd.CmdAdmin,

2
models/access.go

@ -7,7 +7,7 @@ package models
import ( import (
"fmt" "fmt"
"github.com/gogits/gogs/modules/log" log "gopkg.in/clog.v1"
) )
type AccessMode int type AccessMode int

4
models/action.go

@ -15,12 +15,12 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -468,7 +468,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
} }
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil { if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil {
log.Error(4, "updateIssuesCommit: %v", err) log.Error(4, "UpdateIssuesCommit: %v", err)
} }
} }

2
models/admin.go

@ -13,9 +13,9 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

175
models/attachment.go

@ -0,0 +1,175 @@
// Copyright 2017 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"fmt"
"io"
"mime/multipart"
"os"
"path"
"time"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
"github.com/gogits/gogs/modules/setting"
)
// Attachment represent a attachment of issue/comment/release.
type Attachment struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`
IssueID int64 `xorm:"INDEX"`
CommentID int64
ReleaseID int64 `xorm:"INDEX"`
Name string
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (a *Attachment) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
func AttachmentLocalPath(uuid string) string {
return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
}
// LocalPath returns where attachment is stored in local file system.
func (attach *Attachment) LocalPath() string {
return AttachmentLocalPath(attach.UUID)
}
// NewAttachment creates a new attachment object.
func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
attach := &Attachment{
UUID: gouuid.NewV4().String(),
Name: name,
}
localPath := attach.LocalPath()
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
return nil, fmt.Errorf("MkdirAll: %v", err)
}
fw, err := os.Create(localPath)
if err != nil {
return nil, fmt.Errorf("Create: %v", err)
}
defer fw.Close()
if _, err = fw.Write(buf); err != nil {
return nil, fmt.Errorf("Write: %v", err)
} else if _, err = io.Copy(fw, file); err != nil {
return nil, fmt.Errorf("Copy: %v", err)
}
if _, err := x.Insert(attach); err != nil {
return nil, err
}
return attach, nil
}
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
attach := &Attachment{UUID: uuid}
has, err := x.Get(attach)
if err != nil {
return nil, err
} else if !has {
return nil, ErrAttachmentNotExist{0, uuid}
}
return attach, nil
}
func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
if len(uuids) == 0 {
return []*Attachment{}, nil
}
// Silently drop invalid uuids.
attachments := make([]*Attachment, 0, len(uuids))
return attachments, e.In("uuid", uuids).Find(&attachments)
}
// GetAttachmentByUUID returns attachment by given UUID.
func GetAttachmentByUUID(uuid string) (*Attachment, error) {
return getAttachmentByUUID(x, uuid)
}
func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
}
// GetAttachmentsByIssueID returns all attachments of an issue.
func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
return getAttachmentsByIssueID(x, issueID)
}
func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
}
// GetAttachmentsByCommentID returns all attachments if comment by given ID.
func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
return getAttachmentsByCommentID(x, commentID)
}
// DeleteAttachment deletes the given attachment and optionally the associated file.
func DeleteAttachment(a *Attachment, remove bool) error {
_, err := DeleteAttachments([]*Attachment{a}, remove)
return err
}
// DeleteAttachments deletes the given attachments and optionally the associated files.
func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
for i, a := range attachments {
if remove {
if err := os.Remove(a.LocalPath()); err != nil {
return i, err
}
}
if _, err := x.Delete(a); err != nil {
return i, err
}
}
return len(attachments), nil
}
// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByIssueID(issueId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}
// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByCommentID(commentId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}

2
models/issue_comment.go → models/comment.go

@ -11,10 +11,10 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
) )

2
models/git_diff.go

@ -20,11 +20,11 @@ import (
"github.com/sergi/go-diff/diffmatchpatch" "github.com/sergi/go-diff/diffmatchpatch"
"golang.org/x/net/html/charset" "golang.org/x/net/html/charset"
"golang.org/x/text/transform" "golang.org/x/text/transform"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/template/highlight" "github.com/gogits/gogs/modules/template/highlight"

530
models/issue.go

@ -7,20 +7,15 @@ package models
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"mime/multipart"
"os"
"path"
"strings" "strings"
"time" "time"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
gouuid "github.com/satori/go.uuid" log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -818,20 +813,20 @@ type IssuesOptions struct {
SortType string SortType string
} }
// Issues returns a list of issues by given conditions. // buildIssuesQuery returns nil if it foresees there won't be any value returned.
func Issues(opts *IssuesOptions) ([]*Issue, error) { func buildIssuesQuery(opts *IssuesOptions) *xorm.Session {
sess := x.NewSession()
if opts.Page <= 0 { if opts.Page <= 0 {
opts.Page = 1 opts.Page = 1
} }
sess := x.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
if opts.RepoID > 0 { if opts.RepoID > 0 {
sess.Where("issue.repo_id=?", opts.RepoID).And("issue.is_closed=?", opts.IsClosed) sess.Where("issue.repo_id=?", opts.RepoID).And("issue.is_closed=?", opts.IsClosed)
} else if opts.RepoIDs != nil { } else if opts.RepoIDs != nil {
// In case repository IDs are provided but actually no repository has issue. // In case repository IDs are provided but actually no repository has issue.
if len(opts.RepoIDs) == 0 { if len(opts.RepoIDs) == 0 {
return make([]*Issue, 0), nil return nil
} }
sess.In("issue.repo_id", base.Int64sToStrings(opts.RepoIDs)).And("issue.is_closed=?", opts.IsClosed) sess.In("issue.repo_id", base.Int64sToStrings(opts.RepoIDs)).And("issue.is_closed=?", opts.IsClosed)
} else { } else {
@ -882,6 +877,28 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
} }
} }
return sess
}
// IssuesCount returns the number of issues by given conditions.
func IssuesCount(opts *IssuesOptions) (int64, error) {
sess := buildIssuesQuery(opts)
if sess == nil {
return 0, nil
}
return sess.Count(&Issue{})
}
// Issues returns a list of issues by given conditions.
func Issues(opts *IssuesOptions) ([]*Issue, error) {
sess := buildIssuesQuery(opts)
if sess == nil {
return make([]*Issue, 0), nil
}
sess.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
issues := make([]*Issue, 0, setting.UI.IssuePagingNum) issues := make([]*Issue, 0, setting.UI.IssuePagingNum)
if err := sess.Find(&issues); err != nil { if err := sess.Find(&issues); err != nil {
return nil, fmt.Errorf("Find: %v", err) return nil, fmt.Errorf("Find: %v", err)
@ -1332,494 +1349,3 @@ func updateIssueUsersByMentions(e Engine, issueID int64, uids []int64) error {
} }
return nil return nil
} }
// _____ .__.__ __
// / \ |__| | ____ _______/ |_ ____ ____ ____
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
// \/ \/ \/ \/ \/
// Milestone represents a milestone of repository.
type Milestone struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
Name string
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
IsClosed bool
NumIssues int
NumClosedIssues int
NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100).
IsOverDue bool `xorm:"-"`
DeadlineString string `xorm:"-"`
Deadline time.Time `xorm:"-"`
DeadlineUnix int64
ClosedDate time.Time `xorm:"-"`
ClosedDateUnix int64
}
func (m *Milestone) BeforeInsert() {
m.DeadlineUnix = m.Deadline.Unix()
}
func (m *Milestone) BeforeUpdate() {
if m.NumIssues > 0 {
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
} else {
m.Completeness = 0
}
m.DeadlineUnix = m.Deadline.Unix()
m.ClosedDateUnix = m.ClosedDate.Unix()
}
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_closed_issues":
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
case "deadline_unix":
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
if m.Deadline.Year() == 9999 {
return
}
m.DeadlineString = m.Deadline.Format("2006-01-02")
if time.Now().Local().After(m.Deadline) {
m.IsOverDue = true
}
case "closed_date_unix":
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
}
}
// State returns string representation of milestone status.
func (m *Milestone) State() api.StateType {
if m.IsClosed {
return api.STATE_CLOSED
}
return api.STATE_OPEN
}
func (m *Milestone) APIFormat() *api.Milestone {
apiMilestone := &api.Milestone{
ID: m.ID,
State: m.State(),
Title: m.Name,
Description: m.Content,
OpenIssues: m.NumOpenIssues,
ClosedIssues: m.NumClosedIssues,
}
if m.IsClosed {
apiMilestone.Closed = &m.ClosedDate
}
if m.Deadline.Year() < 9999 {
apiMilestone.Deadline = &m.Deadline
}
return apiMilestone
}
// NewMilestone creates new milestone of repository.
func NewMilestone(m *Milestone) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(m); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
return err
}
return sess.Commit()
}
func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
m := &Milestone{
ID: id,
RepoID: repoID,
}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist{id, repoID}
}
return m, nil
}
// GetWebhookByRepoID returns the milestone in a repository.
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
return getMilestoneByRepoID(x, repoID, id)
}
// GetMilestonesByRepoID returns all milestones of a repository.
func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
miles := make([]*Milestone, 0, 10)
return miles, x.Where("repo_id = ?", repoID).Find(&miles)
}
// GetMilestones returns a list of milestones of given repository and status.
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
if page > 0 {
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
}
return miles, sess.Find(&miles)
}
func updateMilestone(e Engine, m *Milestone) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
// UpdateMilestone updates information of given milestone.
func UpdateMilestone(m *Milestone) error {
return updateMilestone(x, m)
}
func countRepoMilestones(e Engine, repoID int64) int64 {
count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
return count
}
// CountRepoMilestones returns number of milestones in given repository.
func CountRepoMilestones(repoID int64) int64 {
return countRepoMilestones(x, repoID)
}
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
return closed
}
// CountRepoClosedMilestones returns number of closed milestones in given repository.
func CountRepoClosedMilestones(repoID int64) int64 {
return countRepoClosedMilestones(x, repoID)
}
// MilestoneStats returns number of open and closed milestones of given repository.
func MilestoneStats(repoID int64) (open int64, closed int64) {
open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
return open, CountRepoClosedMilestones(repoID)
}
// ChangeMilestoneStatus changes the milestone open/closed status.
func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
m.IsClosed = isClosed
if err = updateMilestone(sess, m); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
if issue.MilestoneID == 0 {
return nil
}
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
if issue.IsClosed {
m.NumOpenIssues--
m.NumClosedIssues++
} else {
m.NumOpenIssues++
m.NumClosedIssues--
}
return updateMilestone(e, m)
}
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
// for the milestone associated with the given issue.
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneIssueStats(sess, issue); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
if oldMilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
if err != nil {
return err
}
m.NumIssues--
if issue.IsClosed {
m.NumClosedIssues--
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
return err
}
}
if issue.MilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
m.NumIssues++
if issue.IsClosed {
m.NumClosedIssues++
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
return err
}
}
return updateIssue(e, issue)
}
// ChangeMilestoneAssign changes assignment of milestone for issue.
func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
return err
}
return sess.Commit()
}
// DeleteMilestoneOfRepoByID deletes a milestone from a repository.
func DeleteMilestoneOfRepoByID(repoID, id int64) error {
m, err := GetMilestoneByRepoID(repoID, id)
if err != nil {
if IsErrMilestoneNotExist(err) {
return nil
}
return err
}
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(m.ID).Delete(new(Milestone)); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
}
return sess.Commit()
}
// Attachment represent a attachment of issue/comment/release.
type Attachment struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`
IssueID int64 `xorm:"INDEX"`
CommentID int64
ReleaseID int64 `xorm:"INDEX"`
Name string
Created time.Time `xorm:"-"`
CreatedUnix int64
}
func (a *Attachment) BeforeInsert() {
a.CreatedUnix = time.Now().Unix()
}
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "created_unix":
a.Created = time.Unix(a.CreatedUnix, 0).Local()
}
}
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
func AttachmentLocalPath(uuid string) string {
return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
}
// LocalPath returns where attachment is stored in local file system.
func (attach *Attachment) LocalPath() string {
return AttachmentLocalPath(attach.UUID)
}
// NewAttachment creates a new attachment object.
func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
attach := &Attachment{
UUID: gouuid.NewV4().String(),
Name: name,
}
localPath := attach.LocalPath()
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
return nil, fmt.Errorf("MkdirAll: %v", err)
}
fw, err := os.Create(localPath)
if err != nil {
return nil, fmt.Errorf("Create: %v", err)
}
defer fw.Close()
if _, err = fw.Write(buf); err != nil {
return nil, fmt.Errorf("Write: %v", err)
} else if _, err = io.Copy(fw, file); err != nil {
return nil, fmt.Errorf("Copy: %v", err)
}
if _, err := x.Insert(attach); err != nil {
return nil, err
}
return attach, nil
}
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
attach := &Attachment{UUID: uuid}
has, err := x.Get(attach)
if err != nil {
return nil, err
} else if !has {
return nil, ErrAttachmentNotExist{0, uuid}
}
return attach, nil
}
func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
if len(uuids) == 0 {
return []*Attachment{}, nil
}
// Silently drop invalid uuids.
attachments := make([]*Attachment, 0, len(uuids))
return attachments, e.In("uuid", uuids).Find(&attachments)
}
// GetAttachmentByUUID returns attachment by given UUID.
func GetAttachmentByUUID(uuid string) (*Attachment, error) {
return getAttachmentByUUID(x, uuid)
}
func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
}
// GetAttachmentsByIssueID returns all attachments of an issue.
func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
return getAttachmentsByIssueID(x, issueID)
}
func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
}
// GetAttachmentsByCommentID returns all attachments if comment by given ID.
func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
return getAttachmentsByCommentID(x, commentID)
}
// DeleteAttachment deletes the given attachment and optionally the associated file.
func DeleteAttachment(a *Attachment, remove bool) error {
_, err := DeleteAttachments([]*Attachment{a}, remove)
return err
}
// DeleteAttachments deletes the given attachments and optionally the associated files.
func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
for i, a := range attachments {
if remove {
if err := os.Remove(a.LocalPath()); err != nil {
return i, err
}
}
if _, err := x.Delete(a); err != nil {
return i, err
}
}
return len(attachments), nil
}
// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByIssueID(issueId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}
// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
attachments, err := GetAttachmentsByCommentID(commentId)
if err != nil {
return 0, err
}
return DeleteAttachments(attachments, remove)
}

2
models/issue_mail.go

@ -8,8 +8,8 @@ import (
"fmt" "fmt"
"github.com/Unknwon/com" "github.com/Unknwon/com"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/mailer"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"

2
models/login_source.go

@ -18,10 +18,10 @@ import (
"github.com/go-macaron/binding" "github.com/go-macaron/binding"
"github.com/go-xorm/core" "github.com/go-xorm/core"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/auth/ldap" "github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/auth/pam" "github.com/gogits/gogs/modules/auth/pam"
"github.com/gogits/gogs/modules/log"
) )
type LoginType int type LoginType int

5
models/migrations/migrations.go

@ -18,10 +18,10 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid" gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -72,6 +72,8 @@ var migrations = []Migration{
// v13 -> v14:v0.9.87 // v13 -> v14:v0.9.87
NewMigration("set comment updated with created", setCommentUpdatedWithCreated), NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
// v14 -> v15:v0.9.147
NewMigration("generate and migrate Git hooks", generateAndMigrateGitHooks),
} }
// Migrate database to current version // Migrate database to current version
@ -87,6 +89,7 @@ func Migrate(x *xorm.Engine) error {
} else if !has { } else if !has {
// If the version record does not exist we think // If the version record does not exist we think
// it is a fresh installation and we can skip all migrations. // it is a fresh installation and we can skip all migrations.
currentVersion.ID = 0
currentVersion.Version = int64(_MIN_DB_VER + len(migrations)) currentVersion.Version = int64(_MIN_DB_VER + len(migrations))
if _, err = x.InsertOne(currentVersion); err != nil { if _, err = x.InsertOne(currentVersion); err != nil {

91
models/migrations/v15.go

@ -0,0 +1,91 @@
// Copyright 2017 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/setting"
)
func generateAndMigrateGitHooks(x *xorm.Engine) (err error) {
type Repository struct {
ID int64
OwnerID int64
Name string
}
type User struct {
ID int64
Name string
}
var (
hookNames = []string{"pre-receive", "update", "post-receive"}
hookTpls = []string{
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
}
)
// Cleanup old update.log and http.log files.
filepath.Walk(setting.LogRootPath, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() &&
(strings.HasPrefix(filepath.Base(path), "update.log") ||
strings.HasPrefix(filepath.Base(path), "http.log")) {
os.Remove(path)
}
return nil
})
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if repo.Name == "." || repo.Name == ".." {
return nil
}
user := new(User)
has, err := x.Where("id = ?", repo.OwnerID).Get(user)
if err != nil {
return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err)
} else if !has {
return nil
}
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git"
log.Trace("[%04d]: %s", idx, repoPath)
hookDir := filepath.Join(repoPath, "hooks")
customHookDir := filepath.Join(repoPath, "custom_hooks")
for i, hookName := range hookNames {
oldHookPath := filepath.Join(hookDir, hookName)
newHookPath := filepath.Join(customHookDir, hookName)
// Gogs didn't allow user to set custom update hook thus no migration for it.
// In case user runs this migration multiple times, and custom hook exists,
// we assume it's been migrated already.
if hookName != "update" && com.IsFile(oldHookPath) && !com.IsExist(customHookDir) {
os.MkdirAll(customHookDir, os.ModePerm)
if err = os.Rename(oldHookPath, newHookPath); err != nil {
return fmt.Errorf("move hook file to custom directory '%s' -> '%s': %v", oldHookPath, newHookPath, err)
}
}
if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil {
return fmt.Errorf("write hook file '%s': %v", oldHookPath, err)
}
}
return nil
})
}

349
models/milestone.go

@ -0,0 +1,349 @@
// Copyright 2017 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"time"
"github.com/go-xorm/xorm"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/setting"
)
// Milestone represents a milestone of repository.
type Milestone struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
Name string
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
IsClosed bool
NumIssues int
NumClosedIssues int
NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100).
IsOverDue bool `xorm:"-"`
DeadlineString string `xorm:"-"`
Deadline time.Time `xorm:"-"`
DeadlineUnix int64
ClosedDate time.Time `xorm:"-"`
ClosedDateUnix int64
}
func (m *Milestone) BeforeInsert() {
m.DeadlineUnix = m.Deadline.Unix()
}
func (m *Milestone) BeforeUpdate() {
if m.NumIssues > 0 {
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
} else {
m.Completeness = 0
}
m.DeadlineUnix = m.Deadline.Unix()
m.ClosedDateUnix = m.ClosedDate.Unix()
}
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_closed_issues":
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
case "deadline_unix":
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
if m.Deadline.Year() == 9999 {
return
}
m.DeadlineString = m.Deadline.Format("2006-01-02")
if time.Now().Local().After(m.Deadline) {
m.IsOverDue = true
}
case "closed_date_unix":
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
}
}
// State returns string representation of milestone status.
func (m *Milestone) State() api.StateType {
if m.IsClosed {
return api.STATE_CLOSED
}
return api.STATE_OPEN
}
func (m *Milestone) ChangeStatus(isClosed bool) error {
return ChangeMilestoneStatus(m, isClosed)
}
func (m *Milestone) APIFormat() *api.Milestone {
apiMilestone := &api.Milestone{
ID: m.ID,
State: m.State(),
Title: m.Name,
Description: m.Content,
OpenIssues: m.NumOpenIssues,
ClosedIssues: m.NumClosedIssues,
}
if m.IsClosed {
apiMilestone.Closed = &m.ClosedDate
}
if m.Deadline.Year() < 9999 {
apiMilestone.Deadline = &m.Deadline
}
return apiMilestone
}
// NewMilestone creates new milestone of repository.
func NewMilestone(m *Milestone) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Insert(m); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
return err
}
return sess.Commit()
}
func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
m := &Milestone{
ID: id,
RepoID: repoID,
}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist{id, repoID}
}
return m, nil
}
// GetWebhookByRepoID returns the milestone in a repository.
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
return getMilestoneByRepoID(x, repoID, id)
}
// GetMilestonesByRepoID returns all milestones of a repository.
func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
miles := make([]*Milestone, 0, 10)
return miles, x.Where("repo_id = ?", repoID).Find(&miles)
}
// GetMilestones returns a list of milestones of given repository and status.
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
if page > 0 {
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
}
return miles, sess.Find(&miles)
}
func updateMilestone(e Engine, m *Milestone) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
// UpdateMilestone updates information of given milestone.
func UpdateMilestone(m *Milestone) error {
return updateMilestone(x, m)
}
func countRepoMilestones(e Engine, repoID int64) int64 {
count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
return count
}
// CountRepoMilestones returns number of milestones in given repository.
func CountRepoMilestones(repoID int64) int64 {
return countRepoMilestones(x, repoID)
}
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
return closed
}
// CountRepoClosedMilestones returns number of closed milestones in given repository.
func CountRepoClosedMilestones(repoID int64) int64 {
return countRepoClosedMilestones(x, repoID)
}
// MilestoneStats returns number of open and closed milestones of given repository.
func MilestoneStats(repoID int64) (open int64, closed int64) {
open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
return open, CountRepoClosedMilestones(repoID)
}
// ChangeMilestoneStatus changes the milestone open/closed status.
// If milestone passes with changed values, those values will be
// updated to database as well.
func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
m.IsClosed = isClosed
if err = updateMilestone(sess, m); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
if issue.MilestoneID == 0 {
return nil
}
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
if issue.IsClosed {
m.NumOpenIssues--
m.NumClosedIssues++
} else {
m.NumOpenIssues++
m.NumClosedIssues--
}
return updateMilestone(e, m)
}
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
// for the milestone associated with the given issue.
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneIssueStats(sess, issue); err != nil {
return err
}
return sess.Commit()
}
func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
if oldMilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
if err != nil {
return err
}
m.NumIssues--
if issue.IsClosed {
m.NumClosedIssues--
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
return err
}
}
if issue.MilestoneID > 0 {
m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil {
return err
}
m.NumIssues++
if issue.IsClosed {
m.NumClosedIssues++
}
if err = updateMilestone(e, m); err != nil {
return err
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
return err
}
}
return updateIssue(e, issue)
}
// ChangeMilestoneAssign changes assignment of milestone for issue.
func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
return err
}
return sess.Commit()
}
// DeleteMilestoneOfRepoByID deletes a milestone from a repository.
func DeleteMilestoneOfRepoByID(repoID, id int64) error {
m, err := GetMilestoneByRepoID(repoID, id)
if err != nil {
if IsErrMilestoneNotExist(err) {
return nil
}
return err
}
repo, err := GetRepositoryByID(m.RepoID)
if err != nil {
return err
}
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(m.ID).Delete(new(Milestone)); err != nil {
return err
}
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
return err
}
if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
return err
}
return sess.Commit()
}

2
models/repo_mirror.go → models/mirror.go

@ -11,11 +11,11 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync" "github.com/gogits/gogs/modules/sync"

36
models/models.go

@ -13,6 +13,7 @@ import (
"path" "path"
"strings" "strings"
_ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/core" "github.com/go-xorm/core"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
@ -55,7 +56,6 @@ var (
} }
EnableSQLite3 bool EnableSQLite3 bool
EnableTiDB bool
) )
func init() { func init() {
@ -86,8 +86,8 @@ func LoadConfigs() {
setting.UseMySQL = true setting.UseMySQL = true
case "postgres": case "postgres":
setting.UsePostgreSQL = true setting.UsePostgreSQL = true
case "tidb": case "mssql":
setting.UseTiDB = true setting.UseMSSQL = true
} }
DbCfg.Host = sec.Key("HOST").String() DbCfg.Host = sec.Key("HOST").String()
DbCfg.Name = sec.Key("NAME").String() DbCfg.Name = sec.Key("NAME").String()
@ -114,6 +114,20 @@ func parsePostgreSQLHostPort(info string) (string, string) {
return host, port return host, port
} }
func parseMSSQLHostPort(info string) (string, string) {
host, port := "127.0.0.1", "1433"
if strings.Contains(info, ":") {
host = strings.Split(info, ":")[0]
port = strings.Split(info, ":")[1]
} else if strings.Contains(info, ",") {
host = strings.Split(info, ",")[0]
port = strings.TrimSpace(strings.Split(info, ",")[1])
} else if len(info) > 0 {
host = info
}
return host, port
}
func getEngine() (*xorm.Engine, error) { func getEngine() (*xorm.Engine, error) {
connStr := "" connStr := ""
var Param string = "?" var Param string = "?"
@ -138,6 +152,9 @@ func getEngine() (*xorm.Engine, error) {
connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s", connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode) url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
} }
case "mssql":
host, port := parseMSSQLHostPort(DbCfg.Host)
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd)
case "sqlite3": case "sqlite3":
if !EnableSQLite3 { if !EnableSQLite3 {
return nil, errors.New("This binary version does not build support for SQLite3.") return nil, errors.New("This binary version does not build support for SQLite3.")
@ -146,14 +163,6 @@ func getEngine() (*xorm.Engine, error) {
return nil, fmt.Errorf("Fail to create directories: %v", err) return nil, fmt.Errorf("Fail to create directories: %v", err)
} }
connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc" connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
case "tidb":
if !EnableTiDB {
return nil, errors.New("This binary version does not build support for TiDB.")
}
if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
return nil, fmt.Errorf("Fail to create directories: %v", err)
}
connStr = "goleveldb://" + DbCfg.Path
default: default:
return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type) return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
} }
@ -187,7 +196,12 @@ func SetEngine() (err error) {
if err != nil { if err != nil {
return fmt.Errorf("Fail to create xorm.log: %v", err) return fmt.Errorf("Fail to create xorm.log: %v", err)
} }
if setting.ProdMode {
x.SetLogger(xorm.NewSimpleLogger3(f, xorm.DEFAULT_LOG_PREFIX, xorm.DEFAULT_LOG_FLAG, core.LOG_WARNING))
} else {
x.SetLogger(xorm.NewSimpleLogger(f)) x.SetLogger(xorm.NewSimpleLogger(f))
}
x.ShowSQL(true) x.ShowSQL(true)
return nil return nil
} }

18
models/models_tidb.go

@ -1,18 +0,0 @@
// +build tidb go1.4.2
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
_ "github.com/go-xorm/tidb"
"github.com/ngaut/log"
_ "github.com/pingcap/tidb"
)
func init() {
EnableTiDB = true
log.SetLevelByString("error")
}

2
models/org.go

@ -11,9 +11,9 @@ import (
"strings" "strings"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
) )
var ( var (

25
models/org_team.go

@ -8,6 +8,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"github.com/go-xorm/xorm"
) )
const OWNER_TEAM = "Owners" const OWNER_TEAM = "Owners"
@ -26,6 +28,16 @@ type Team struct {
NumMembers int NumMembers int
} }
func (t *Team) AfterSet(colName string, _ xorm.Cell) {
switch colName {
case "num_repos":
// LEGACY [0.11]: this is backward compatibility bug fix for https://github.com/gogits/gogs/issues/3671
if t.NumRepos < 0 {
t.NumRepos = 0
}
}
}
// IsOwnerTeam returns true if team is owner team. // IsOwnerTeam returns true if team is owner team.
func (t *Team) IsOwnerTeam() bool { func (t *Team) IsOwnerTeam() bool {
return t.Name == OWNER_TEAM return t.Name == OWNER_TEAM
@ -194,11 +206,24 @@ func (t *Team) RemoveRepository(repoID int64) error {
return sess.Commit() return sess.Commit()
} }
var reservedTeamNames = []string{"new"}
// IsUsableTeamName return an error if given name is a reserved name or pattern.
func IsUsableTeamName(name string) error {
return isUsableName(reservedTeamNames, nil, name)
}
// NewTeam creates a record of new team. // NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID. // It's caller's responsibility to assign organization ID.
func NewTeam(t *Team) error { func NewTeam(t *Team) error {
if len(t.Name) == 0 { if len(t.Name) == 0 {
return errors.New("empty team name") return errors.New("empty team name")
} else if t.OrgID == 0 {
return errors.New("OrgID is not assigned")
}
if err := IsUsableTeamName(t.Name); err != nil {
return err
} }
has, err := x.Id(t.OrgID).Get(new(User)) has, err := x.Id(t.OrgID).Get(new(User))

18
models/pull.go

@ -13,11 +13,11 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync" "github.com/gogits/gogs/modules/sync"
@ -364,7 +364,7 @@ func (pr *PullRequest) testPatch() (err error) {
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath) log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil { if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {
return fmt.Errorf("UpdateLocalCopy: %v", err) return fmt.Errorf("UpdateLocalCopy [%d]: %v", pr.BaseRepoID, err)
} }
pr.Status = PULL_REQUEST_STATUS_CHECKING pr.Status = PULL_REQUEST_STATUS_CHECKING
@ -621,18 +621,18 @@ func (pr *PullRequest) AddToTaskQueue() {
type PullRequestList []*PullRequest type PullRequestList []*PullRequest
func (prs PullRequestList) loadAttributes(e Engine) error { func (prs PullRequestList) loadAttributes(e Engine) (err error) {
if len(prs) == 0 { if len(prs) == 0 {
return nil return nil
} }
// Load issues. // Load issues
issueIDs := make([]int64, 0, len(prs)) issueIDs := make([]int64, 0, len(prs))
for i := range prs { for i := range prs {
issueIDs = append(issueIDs, prs[i].IssueID) issueIDs = append(issueIDs, prs[i].IssueID)
} }
issues := make([]*Issue, 0, len(issueIDs)) issues := make([]*Issue, 0, len(issueIDs))
if err := e.Where("id > 0").In("id", issueIDs).Find(&issues); err != nil { if err = e.Where("id > 0").In("id", issueIDs).Find(&issues); err != nil {
return fmt.Errorf("find issues: %v", err) return fmt.Errorf("find issues: %v", err)
} }
@ -643,6 +643,14 @@ func (prs PullRequestList) loadAttributes(e Engine) error {
for i := range prs { for i := range prs {
prs[i].Issue = set[prs[i].IssueID] prs[i].Issue = set[prs[i].IssueID]
} }
// Load attributes
for i := range prs {
if err = prs[i].loadAttributes(e); err != nil {
return fmt.Errorf("loadAttributes [%d]: %v", prs[i].ID, err)
}
}
return nil return nil
} }

80
models/repo.go

@ -23,23 +23,19 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/mcuadros/go-version" "github.com/mcuadros/go-version"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
git "github.com/gogits/git-module" git "github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/bindata" "github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync" "github.com/gogits/gogs/modules/sync"
) )
const (
_TPL_UPDATE_HOOK = "#!/usr/bin/env %s\n%s update $1 $2 $3 --config='%s'\n"
)
var repoWorkingPool = sync.NewExclusivePool() var repoWorkingPool = sync.NewExclusivePool()
var ( var (
@ -115,15 +111,17 @@ func NewRepoContext() {
} }
// Check Git version. // Check Git version.
gitVer, err := git.BinVersion() var err error
setting.Git.Version, err = git.BinVersion()
if err != nil { if err != nil {
log.Fatal(4, "Fail to get Git version: %v", err) log.Fatal(4, "Fail to get Git version: %v", err)
} }
log.Info("Git Version: %s", gitVer) log.Info("Git Version: %s", setting.Git.Version)
if version.Compare("1.7.1", gitVer, ">") { if version.Compare("1.7.1", setting.Git.Version, ">") {
log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1") log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1")
} }
git.HookDir = "custom_hooks"
// Git requires setting user.name and user.email in order to commit changes. // Git requires setting user.name and user.email in order to commit changes.
for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} { for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} {
@ -467,7 +465,7 @@ func (repo *Repository) DescriptionHtml() template.HTML {
} }
func (repo *Repository) LocalCopyPath() string { func (repo *Repository) LocalCopyPath() string {
return path.Join(setting.AppDataPath, "tmp/local-rpeo", com.ToStr(repo.ID)) return path.Join(setting.AppDataPath, "tmp/local-repo", com.ToStr(repo.ID))
} }
// UpdateLocalCopy pulls latest changes of given branch from repoPath to localPath. // UpdateLocalCopy pulls latest changes of given branch from repoPath to localPath.
@ -653,7 +651,8 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
Quiet: true, Quiet: true,
Timeout: migrateTimeout, Timeout: migrateTimeout,
}); err != nil { }); err != nil {
log.Info("Clone wiki: %v", err) log.Trace("Fail to clone wiki: %v", err)
os.RemoveAll(wikiPath)
} }
} }
@ -713,20 +712,33 @@ func cleanUpMigrateGitConfig(configPath string) error {
return nil return nil
} }
func createUpdateHook(repoPath string) error { var hooksTpls = map[string]string{
return git.SetUpdateHook(repoPath, "pre-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n",
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)) "update": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n",
"post-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n",
}
func createDelegateHooks(repoPath string) (err error) {
for _, name := range git.HookNames {
hookPath := filepath.Join(repoPath, "hooks", name)
if err = ioutil.WriteFile(hookPath,
[]byte(fmt.Sprintf(hooksTpls[name], setting.ScriptType, setting.AppPath, setting.CustomConf)),
os.ModePerm); err != nil {
return fmt.Errorf("create delegate hook '%s': %v", hookPath, err)
}
}
return nil
} }
// Finish migrating repository and/or wiki with things that don't need to be done for mirrors. // Finish migrating repository and/or wiki with things that don't need to be done for mirrors.
func CleanUpMigrateInfo(repo *Repository) (*Repository, error) { func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
repoPath := repo.RepoPath() repoPath := repo.RepoPath()
if err := createUpdateHook(repoPath); err != nil { if err := createDelegateHooks(repoPath); err != nil {
return repo, fmt.Errorf("createUpdateHook: %v", err) return repo, fmt.Errorf("createDelegateHooks: %v", err)
} }
if repo.HasWiki() { if repo.HasWiki() {
if err := createUpdateHook(repo.WikiPath()); err != nil { if err := createDelegateHooks(repo.WikiPath()); err != nil {
return repo, fmt.Errorf("createUpdateHook (wiki): %v", err) return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err)
} }
} }
@ -735,7 +747,7 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
} }
if repo.HasWiki() { if repo.HasWiki() {
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil { if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil {
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err) return repo, fmt.Errorf("cleanUpMigrateGitConfig.(wiki): %v", err)
} }
} }
@ -860,8 +872,8 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
// Init bare new repository. // Init bare new repository.
if err = git.InitRepository(repoPath, true); err != nil { if err = git.InitRepository(repoPath, true); err != nil {
return fmt.Errorf("InitRepository: %v", err) return fmt.Errorf("InitRepository: %v", err)
} else if err = createUpdateHook(repoPath); err != nil { } else if err = createDelegateHooks(repoPath); err != nil {
return fmt.Errorf("createUpdateHook: %v", err) return fmt.Errorf("createDelegateHooks: %v", err)
} }
tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond())) tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
@ -904,6 +916,7 @@ var (
reservedRepoPatterns = []string{"*.git", "*.wiki"} reservedRepoPatterns = []string{"*.git", "*.wiki"}
) )
// IsUsableRepoName return an error if given name is a reserved name or pattern.
func IsUsableRepoName(name string) error { func IsUsableRepoName(name string) error {
return isUsableName(reservedRepoNames, reservedRepoPatterns, name) return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
} }
@ -1228,7 +1241,7 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
return fmt.Errorf("GetRepositoryByName: %v", err) return fmt.Errorf("GetRepositoryByName: %v", err)
} }
// Change repository directory name. // Change repository directory name
if err = os.Rename(repo.RepoPath(), RepoPath(u.Name, newRepoName)); err != nil { if err = os.Rename(repo.RepoPath(), RepoPath(u.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository directory: %v", err) return fmt.Errorf("rename repository directory: %v", err)
} }
@ -1241,6 +1254,7 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error)
RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
} }
RemoveAllWithNotice("Delete repository local copy", repo.LocalCopyPath())
return nil return nil
} }
@ -1413,6 +1427,10 @@ func DeleteRepository(uid, repoID int64) error {
return err return err
} }
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
// Remove repository files. // Remove repository files.
repoPath := repo.repoPath(sess) repoPath := repo.repoPath(sess)
RemoveAllWithNotice("Delete repository files", repoPath) RemoveAllWithNotice("Delete repository files", repoPath)
@ -1424,10 +1442,6 @@ func DeleteRepository(uid, repoID int64) error {
RemoveAllWithNotice("Delete attachment", attachmentPaths[i]) RemoveAllWithNotice("Delete attachment", attachmentPaths[i])
} }
if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err)
}
if repo.NumForks > 0 { if repo.NumForks > 0 {
if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil { if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
log.Error(4, "reset 'fork_id' and 'is_fork': %v", err) log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
@ -1644,12 +1658,12 @@ func ReinitMissingRepositories() error {
return nil return nil
} }
// RewriteRepositoryUpdateHook rewrites all repositories' update hook. // SyncRepositoryHooks rewrites all repositories' pre-receive, update and post-receive hooks
func RewriteRepositoryUpdateHook() error { // to make sure the binary and custom conf path are up-to-date.
func SyncRepositoryHooks() error {
return x.Where("id > 0").Iterate(new(Repository), return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error { func(idx int, bean interface{}) error {
repo := bean.(*Repository) return createDelegateHooks(bean.(*Repository).RepoPath())
return createUpdateHook(repo.RepoPath())
}) })
} }
@ -2094,21 +2108,21 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
repoPath := RepoPath(u.Name, repo.Name) repoPath := RepoPath(u.Name, repo.Name)
_, stderr, err := process.ExecTimeout(10*time.Minute, _, stderr, err := process.ExecTimeout(10*time.Minute,
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name), fmt.Sprintf("ForkRepository 'git clone': %s/%s", u.Name, repo.Name),
"git", "clone", "--bare", oldRepo.RepoPath(), repoPath) "git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("git clone: %v", stderr) return nil, fmt.Errorf("git clone: %v", stderr)
} }
_, stderr, err = process.ExecDir(-1, _, stderr, err = process.ExecDir(-1,
repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath), repoPath, fmt.Sprintf("ForkRepository 'git update-server-info': %s", repoPath),
"git", "update-server-info") "git", "update-server-info")
if err != nil { if err != nil {
return nil, fmt.Errorf("git update-server-info: %v", err) return nil, fmt.Errorf("git update-server-info: %v", err)
} }
if err = createUpdateHook(repoPath); err != nil { if err = createDelegateHooks(repoPath); err != nil {
return nil, fmt.Errorf("createUpdateHook: %v", err) return nil, fmt.Errorf("createDelegateHooks: %v", err)
} }
return repo, sess.Commit() return repo, sess.Commit()

23
models/repo_collaboration.go

@ -6,6 +6,8 @@ package models
import ( import (
"fmt" "fmt"
api "github.com/gogits/go-gogs-client"
) )
// Collaboration represent the relation between an individual and a repository. // Collaboration represent the relation between an individual and a repository.
@ -29,6 +31,16 @@ func (c *Collaboration) ModeI18nKey() string {
} }
} }
//IsCollaborator returns true if the user is a collaborator
func (repo *Repository) IsCollaborator(uid int64) (bool, error) {
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: uid,
}
return x.Get(collaboration)
}
// AddCollaborator adds new collaboration to a repository with default access mode. // AddCollaborator adds new collaboration to a repository with default access mode.
func (repo *Repository) AddCollaborator(u *User) error { func (repo *Repository) AddCollaborator(u *User) error {
collaboration := &Collaboration{ collaboration := &Collaboration{
@ -77,6 +89,17 @@ type Collaborator struct {
Collaboration *Collaboration Collaboration *Collaboration
} }
func (c *Collaborator) APIFormat() *api.Collaborator {
return &api.Collaborator{
User: c.User.APIFormat(),
Permissions: api.Permission{
Admin: c.Collaboration.Mode >= ACCESS_MODE_ADMIN,
Push: c.Collaboration.Mode >= ACCESS_MODE_WRITE,
Pull: c.Collaboration.Mode >= ACCESS_MODE_READ,
},
}
}
func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) { func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) {
collaborations, err := repo.getCollaborations(e) collaborations, err := repo.getCollaborations(e)
if err != nil { if err != nil {

2
models/repo_editor.go

@ -17,10 +17,10 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
gouuid "github.com/satori/go.uuid" gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
git "github.com/gogits/git-module" git "github.com/gogits/git-module"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

16
models/ssh_key.go

@ -21,9 +21,9 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -84,8 +84,13 @@ func (k *PublicKey) OmitEmail() string {
} }
// AuthorizedString returns formatted public key string for authorized_keys file. // AuthorizedString returns formatted public key string for authorized_keys file.
func (key *PublicKey) AuthorizedString() string { func (k *PublicKey) AuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, key.ID, setting.CustomConf, key.Content) return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, k.ID, setting.CustomConf, k.Content)
}
// IsDeployKey returns true if the public key is used as deploy key.
func (k *PublicKey) IsDeployKey() bool {
return k.Type == KEY_TYPE_DEPLOY
} }
func extractTypeFromBase64Key(key string) (string, error) { func extractTypeFromBase64Key(key string) (string, error) {
@ -380,9 +385,10 @@ func addKey(e Engine, key *PublicKey) (err error) {
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil { if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil {
return err return err
} }
stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
stdout, stderr, err := process.Exec("AddPublicKey", setting.SSH.KeygenPath, "-lf", tmpPath)
if err != nil { if err != nil {
return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr) return fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
} else if len(stdout) < 2 { } else if len(stdout) < 2 {
return errors.New("not enough output for calculating fingerprint: " + stdout) return errors.New("not enough output for calculating fingerprint: " + stdout)
} }

6
models/update.go

@ -10,9 +10,9 @@ import (
"os/exec" "os/exec"
"strings" "strings"
git "github.com/gogits/git-module" log "gopkg.in/clog.v1"
"github.com/gogits/gogs/modules/log" git "github.com/gogits/git-module"
) )
type UpdateTask struct { type UpdateTask struct {
@ -101,7 +101,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
} }
if isDelRef { if isDelRef {
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %s", log.Trace("Reference '%s' has been deleted from '%s/%s' by %s",
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName) opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
return nil return nil
} }

10
models/user.go

@ -25,13 +25,13 @@ import (
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/nfnt/resize" "github.com/nfnt/resize"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
log "gopkg.in/clog.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/avatar" "github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -170,6 +170,10 @@ func (u *User) CanCreateRepo() bool {
return u.NumRepos < u.MaxRepoCreation return u.NumRepos < u.MaxRepoCreation
} }
func (u *User) CanCreateOrganization() bool {
return !setting.Admin.DisableRegularOrgCreation || u.IsAdmin
}
// CanEditGitHook returns true if user can edit Git hooks. // CanEditGitHook returns true if user can edit Git hooks.
func (u *User) CanEditGitHook() bool { func (u *User) CanEditGitHook() bool {
return u.IsAdmin || u.AllowGitHook return u.IsAdmin || u.AllowGitHook
@ -193,6 +197,10 @@ func (u *User) HomeLink() string {
return setting.AppSubUrl + "/" + u.Name return setting.AppSubUrl + "/" + u.Name
} }
func (u *User) HTMLURL() string {
return setting.AppUrl + u.Name
}
// GenerateEmailActivateCode generates an activate code based on user information and given e-mail. // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
func (u *User) GenerateEmailActivateCode(email string) string { func (u *User) GenerateEmailActivateCode(email string) string {
code := base.CreateTimeLimitCode( code := base.CreateTimeLimitCode(

6
models/webhook.go

@ -14,11 +14,11 @@ import (
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid" gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
api "github.com/gogits/go-gogs-client" api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/modules/httplib" "github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync" "github.com/gogits/gogs/modules/sync"
) )
@ -476,7 +476,9 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks. // Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
switch w.HookTaskType { switch w.HookTaskType {
case SLACK: case SLACK:
payloader, err = GetSlackPayload(p, event, w.Meta) // FIXME: dirty fix for buggy support of Discord for Slack-type webhook.
// Should remove this if we want to support Discord fully as its own.
payloader, err = GetSlackPayload(strings.Contains(w.URL, ".discordapp.com/"), p, event, w.Meta)
if err != nil { if err != nil {
return fmt.Errorf("GetSlackPayload: %v", err) return fmt.Errorf("GetSlackPayload: %v", err)
} }

32
models/webhook_slack.go

@ -72,13 +72,21 @@ func SlackLinkFormatter(url string, text string) string {
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text)) return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
} }
func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) { func replaceBadCharsForDiscord(in string) string {
// created tag/branch return strings.NewReplacer("[", "", "]", ":", ":", "/").Replace(in)
}
func getSlackCreatePayload(isDiscord bool, p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
// Created tag/branch
refName := git.RefEndName(p.Ref) refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName) refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName) format := "[%s:%s] %s created by %s"
if isDiscord {
format = replaceBadCharsForDiscord(format)
}
text := fmt.Sprintf(format, repoLink, refLink, p.RefType, p.Sender.UserName)
return &SlackPayload{ return &SlackPayload{
Channel: slack.Channel, Channel: slack.Channel,
@ -88,7 +96,7 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa
}, nil }, nil
} }
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
// n new commits // n new commits
var ( var (
branchName = git.RefEndName(p.Ref) branchName = git.RefEndName(p.Ref)
@ -109,7 +117,11 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName) branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName) format := "[%s:%s] %s pushed by %s"
if isDiscord {
format = replaceBadCharsForDiscord(format)
}
text := fmt.Sprintf(format, repoLink, branchLink, commitString, p.Pusher.UserName)
var attachmentText string var attachmentText string
// for each commit, generate attachment text // for each commit, generate attachment text
@ -133,7 +145,7 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
}, nil }, nil
} }
func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName) senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index), titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)) fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
@ -181,7 +193,7 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
}, nil }, nil
} }
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) { func GetSlackPayload(isDiscord bool, p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
s := new(SlackPayload) s := new(SlackPayload)
slack := &SlackMeta{} slack := &SlackMeta{}
@ -191,11 +203,11 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP
switch event { switch event {
case HOOK_EVENT_CREATE: case HOOK_EVENT_CREATE:
return getSlackCreatePayload(p.(*api.CreatePayload), slack) return getSlackCreatePayload(isDiscord, p.(*api.CreatePayload), slack)
case HOOK_EVENT_PUSH: case HOOK_EVENT_PUSH:
return getSlackPushPayload(p.(*api.PushPayload), slack) return getSlackPushPayload(isDiscord, p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST: case HOOK_EVENT_PULL_REQUEST:
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack) return getSlackPullRequestPayload(isDiscord, p.(*api.PullRequestPayload), slack)
} }
return s, nil return s, nil

4
models/wiki.go

@ -64,8 +64,8 @@ func (repo *Repository) InitWiki() error {
if err := git.InitRepository(repo.WikiPath(), true); err != nil { if err := git.InitRepository(repo.WikiPath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err) return fmt.Errorf("InitRepository: %v", err)
} else if err = createUpdateHook(repo.WikiPath()); err != nil { } else if err = createDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createUpdateHook: %v", err) return fmt.Errorf("createDelegateHooks: %v", err)
} }
return nil return nil
} }

2
modules/auth/auth.go

@ -13,11 +13,11 @@ import (
"github.com/go-macaron/binding" "github.com/go-macaron/binding"
"github.com/go-macaron/session" "github.com/go-macaron/session"
gouuid "github.com/satori/go.uuid" gouuid "github.com/satori/go.uuid"
log "gopkg.in/clog.v1"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

43
modules/auth/ldap/ldap.go

@ -11,9 +11,8 @@ import (
"fmt" "fmt"
"strings" "strings"
log "gopkg.in/clog.v1"
"gopkg.in/ldap.v2" "gopkg.in/ldap.v2"
"github.com/gogits/gogs/modules/log"
) )
type SecurityProtocol int type SecurityProtocol int
@ -50,7 +49,7 @@ func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
// See http://tools.ietf.org/search/rfc4515 // See http://tools.ietf.org/search/rfc4515
badCharacters := "\x00()*\\" badCharacters := "\x00()*\\"
if strings.ContainsAny(username, badCharacters) { if strings.ContainsAny(username, badCharacters) {
log.Debug("'%s' contains invalid query characters. Aborting.", username) log.Trace("Username contains invalid query characters: %s", username)
return "", false return "", false
} }
@ -61,7 +60,7 @@ func (ls *Source) sanitizedUserDN(username string) (string, bool) {
// See http://tools.ietf.org/search/rfc4514: "special characters" // See http://tools.ietf.org/search/rfc4514: "special characters"
badCharacters := "\x00()*\\,='\"#+;<>" badCharacters := "\x00()*\\,='\"#+;<>"
if strings.ContainsAny(username, badCharacters) || strings.HasPrefix(username, " ") || strings.HasSuffix(username, " ") { if strings.ContainsAny(username, badCharacters) || strings.HasPrefix(username, " ") || strings.HasSuffix(username, " ") {
log.Debug("'%s' contains invalid DN characters. Aborting.", username) log.Trace("Username contains invalid query characters: %s", username)
return "", false return "", false
} }
@ -73,12 +72,12 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
if ls.BindDN != "" && ls.BindPassword != "" { if ls.BindDN != "" && ls.BindPassword != "" {
err := l.Bind(ls.BindDN, ls.BindPassword) err := l.Bind(ls.BindDN, ls.BindPassword)
if err != nil { if err != nil {
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err) log.Trace("Failed to bind as BindDN '%s': %v", ls.BindDN, err)
return "", false return "", false
} }
log.Trace("Bound as BindDN %s", ls.BindDN) log.Trace("Bound as BindDN: %s", ls.BindDN)
} else { } else {
log.Trace("Proceeding with anonymous LDAP search.") log.Trace("Proceeding with anonymous LDAP search")
} }
// A search for the user. // A search for the user.
@ -87,7 +86,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
return "", false return "", false
} }
log.Trace("Searching for DN using filter %s and base %s", userFilter, ls.UserBase) log.Trace("Searching for DN using filter '%s' and base '%s'", userFilter, ls.UserBase)
search := ldap.NewSearchRequest( search := ldap.NewSearchRequest(
ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0,
false, userFilter, []string{}, nil) false, userFilter, []string{}, nil)
@ -95,10 +94,10 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
// Ensure we found a user // Ensure we found a user
sr, err := l.Search(search) sr, err := l.Search(search)
if err != nil || len(sr.Entries) < 1 { if err != nil || len(sr.Entries) < 1 {
log.Debug("Failed search using filter[%s]: %v", userFilter, err) log.Trace("Failed search using filter '%s': %v", userFilter, err)
return "", false return "", false
} else if len(sr.Entries) > 1 { } else if len(sr.Entries) > 1 {
log.Debug("Filter '%s' returned more than one user.", userFilter) log.Trace("Filter '%s' returned more than one user", userFilter)
return "", false return "", false
} }
@ -112,7 +111,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
} }
func dial(ls *Source) (*ldap.Conn, error) { func dial(ls *Source) (*ldap.Conn, error) {
log.Trace("Dialing LDAP with security protocol (%v) without verifying: %v", ls.SecurityProtocol, ls.SkipVerify) log.Trace("Dialing LDAP with security protocol '%v' without verifying: %v", ls.SecurityProtocol, ls.SkipVerify)
tlsCfg := &tls.Config{ tlsCfg := &tls.Config{
ServerName: ls.Host, ServerName: ls.Host,
@ -141,7 +140,7 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
log.Trace("Binding with userDN: %s", userDN) log.Trace("Binding with userDN: %s", userDN)
err := l.Bind(userDN, passwd) err := l.Bind(userDN, passwd)
if err != nil { if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err) log.Trace("LDAP authentication failed for '%s': %v", userDN, err)
return err return err
} }
log.Trace("Bound successfully with userDN: %s", userDN) log.Trace("Bound successfully with userDN: %s", userDN)
@ -152,12 +151,12 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) { func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, string, string, string, bool, bool) {
// See https://tools.ietf.org/search/rfc4513#section-5.1.2 // See https://tools.ietf.org/search/rfc4513#section-5.1.2
if len(passwd) == 0 { if len(passwd) == 0 {
log.Debug("Auth. failed for %s, password cannot be empty") log.Trace("authentication failed for '%s' with empty password")
return "", "", "", "", false, false return "", "", "", "", false, false
} }
l, err := dial(ls) l, err := dial(ls)
if err != nil { if err != nil {
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err) log.Error(4, "LDAP connect failed for '%s': %v", ls.Host, err)
ls.Enabled = false ls.Enabled = false
return "", "", "", "", false, false return "", "", "", "", false, false
} }
@ -173,7 +172,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
return "", "", "", "", false, false return "", "", "", "", false, false
} }
} else { } else {
log.Trace("LDAP will use BindDN.") log.Trace("LDAP will use BindDN")
var found bool var found bool
userDN, found = ls.findUserDN(l, name) userDN, found = ls.findUserDN(l, name)
@ -195,7 +194,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
return "", "", "", "", false, false return "", "", "", "", false, false
} }
log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter %s and base %s", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN) log.Trace("Fetching attributes '%v', '%v', '%v', '%v' with filter '%s' and base '%s'", ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail, userFilter, userDN)
search := ldap.NewSearchRequest( search := ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter,
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail}, []string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
@ -203,13 +202,13 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
sr, err := l.Search(search) sr, err := l.Search(search)
if err != nil { if err != nil {
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err) log.Error(4, "LDAP search failed: %v", err)
return "", "", "", "", false, false return "", "", "", "", false, false
} else if len(sr.Entries) < 1 { } else if len(sr.Entries) < 1 {
if directBind { if directBind {
log.Error(4, "User filter inhibited user login.") log.Error(4, "User filter inhibited user login")
} else { } else {
log.Error(4, "LDAP Search failed unexpectedly! (0 entries)") log.Error(4, "LDAP search failed: 0 entries")
} }
return "", "", "", "", false, false return "", "", "", "", false, false
@ -222,7 +221,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
isAdmin := false isAdmin := false
if len(ls.AdminFilter) > 0 { if len(ls.AdminFilter) > 0 {
log.Trace("Checking admin with filter %s and base %s", ls.AdminFilter, userDN) log.Trace("Checking admin with filter '%s' and base '%s'", ls.AdminFilter, userDN)
search = ldap.NewSearchRequest( search = ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter, userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
[]string{ls.AttributeName}, []string{ls.AttributeName},
@ -230,9 +229,9 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
sr, err = l.Search(search) sr, err = l.Search(search)
if err != nil { if err != nil {
log.Error(4, "LDAP Admin Search failed unexpectedly! (%v)", err) log.Error(4, "LDAP admin search failed: %v", err)
} else if len(sr.Entries) < 1 { } else if len(sr.Entries) < 1 {
log.Error(4, "LDAP Admin Search failed") log.Error(4, "LDAP admin search failed: 0 entries")
} else { } else {
isAdmin = true isAdmin = true
} }

2
modules/auth/user_form.go

@ -31,7 +31,7 @@ type InstallForm struct {
SMTPHost string SMTPHost string
SMTPFrom string SMTPFrom string
SMTPEmail string `binding:"OmitEmpty;Email;MaxSize(254)" locale:"install.mailer_user"` SMTPUser string `binding:"OmitEmpty;MaxSize(254)" locale:"install.mailer_user"`
SMTPPasswd string SMTPPasswd string
RegisterConfirm bool RegisterConfirm bool
MailNotify bool MailNotify bool

13
modules/base/tool.go

@ -22,10 +22,10 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/Unknwon/i18n" "github.com/Unknwon/i18n"
log "gopkg.in/clog.v1"
"github.com/gogits/chardet" "github.com/gogits/chardet"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -52,17 +52,17 @@ func ShortSha(sha1 string) string {
func DetectEncoding(content []byte) (string, error) { func DetectEncoding(content []byte) (string, error) {
if utf8.Valid(content) { if utf8.Valid(content) {
log.Debug("Detected encoding: utf-8 (fast)") log.Trace("Detected encoding: utf-8 (fast)")
return "UTF-8", nil return "UTF-8", nil
} }
result, err := chardet.NewTextDetector().DetectBest(content) result, err := chardet.NewTextDetector().DetectBest(content)
if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 {
log.Debug("Using default AnsiCharset: %s", setting.Repository.AnsiCharset) log.Trace("Using default AnsiCharset: %s", setting.Repository.AnsiCharset)
return setting.Repository.AnsiCharset, err return setting.Repository.AnsiCharset, err
} }
log.Debug("Detected encoding: %s", result.Charset) log.Trace("Detected encoding: %s", result.Charset)
return result.Charset, err return result.Charset, err
} }
@ -181,11 +181,12 @@ func HashEmail(email string) string {
// which includes app sub-url as prefix. However, it is possible // which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service. // to return full URL if user enables Gravatar-like service.
func AvatarLink(email string) (url string) { func AvatarLink(email string) (url string) {
if setting.EnableFederatedAvatar && setting.LibravatarService != nil { if setting.EnableFederatedAvatar && setting.LibravatarService != nil &&
len(email) > 0 {
var err error var err error
url, err = setting.LibravatarService.FromEmail(email) url, err = setting.LibravatarService.FromEmail(email)
if err != nil { if err != nil {
log.Error(4, "LibravatarService.FromEmail [%s]: %v", email, err) log.Error(3, "LibravatarService.FromEmail [%s]: %v", email, err)
} }
} }
if len(url) == 0 && !setting.DisableGravatar { if len(url) == 0 && !setting.DisableGravatar {

92
modules/bindata/bindata.go

File diff suppressed because one or more lines are too long

2
modules/context/api.go

@ -9,10 +9,10 @@ import (
"strings" "strings"
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
log "gopkg.in/clog.v1"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

27
modules/context/context.go

@ -16,12 +16,12 @@ import (
"github.com/go-macaron/csrf" "github.com/go-macaron/csrf"
"github.com/go-macaron/i18n" "github.com/go-macaron/i18n"
"github.com/go-macaron/session" "github.com/go-macaron/session"
log "gopkg.in/clog.v1"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -73,7 +73,7 @@ func (ctx *Context) HasValue(name string) bool {
// HTML calls Context.HTML and converts template name to string. // HTML calls Context.HTML and converts template name to string.
func (ctx *Context) HTML(status int, name base.TplName) { func (ctx *Context) HTML(status int, name base.TplName) {
log.Debug("Template: %s", name) log.Trace("Template: %s", name)
ctx.Context.HTML(status, string(name)) ctx.Context.HTML(status, string(name))
} }
@ -89,22 +89,24 @@ func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}
// Handle handles and logs error by given status. // Handle handles and logs error by given status.
func (ctx *Context) Handle(status int, title string, err error) { func (ctx *Context) Handle(status int, title string, err error) {
if err != nil {
log.Error(4, "%s: %v", title, err)
if macaron.Env != macaron.PROD {
ctx.Data["ErrorMsg"] = err
}
}
switch status { switch status {
case 404: case 404:
ctx.Data["Title"] = "Page Not Found" ctx.Data["Title"] = "Page Not Found"
case 500: case 500:
ctx.Data["Title"] = "Internal Server Error" ctx.Data["Title"] = "Internal Server Error"
log.Error(4, "%s: %v", title, err)
if !setting.ProdMode || (ctx.IsSigned && ctx.User.IsAdmin) {
ctx.Data["ErrorMsg"] = err
}
} }
ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status))) ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
} }
// NotFound simply renders the 404 page.
func (ctx *Context) NotFound() {
ctx.Handle(404, "", nil)
}
// NotFoundOrServerError use error check function to determine if the error // NotFoundOrServerError use error check function to determine if the error
// is about not found. It responses with 404 status code for not found error, // is about not found. It responses with 404 status code for not found error,
// or error context description for logging purpose of 500 server error. // or error context description for logging purpose of 500 server error.
@ -118,9 +120,6 @@ func (ctx *Context) NotFoundOrServerError(title string, errck func(error) bool,
} }
func (ctx *Context) HandleText(status int, title string) { func (ctx *Context) HandleText(status int, title string) {
if (status/100 == 4) || (status/100 == 5) {
log.Error(4, "%s", title)
}
ctx.PlainText(status, []byte(title)) ctx.PlainText(status, []byte(title))
} }
@ -191,8 +190,8 @@ func Contexter() macaron.Handler {
ctx.Data["CsrfToken"] = x.GetToken() ctx.Data["CsrfToken"] = x.GetToken()
ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`) ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
log.Debug("Session ID: %s", sess.ID()) log.Trace("Session ID: %s", sess.ID())
log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"]) log.Trace("CSRF Token: %v", ctx.Data["CsrfToken"])
ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding

20
modules/context/repo.go

@ -11,13 +11,13 @@ import (
"strings" "strings"
"github.com/Unknwon/com" "github.com/Unknwon/com"
log "gopkg.in/clog.v1"
"gopkg.in/editorconfig/editorconfig-core-go.v1" "gopkg.in/editorconfig/editorconfig-core-go.v1"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
"github.com/gogits/git-module" "github.com/gogits/git-module"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -164,7 +164,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
earlyResponseForGoGetMeta(ctx) earlyResponseForGoGetMeta(ctx)
return return
} }
ctx.Handle(404, "GetUserByName", err) ctx.NotFound()
} else { } else {
ctx.Handle(500, "GetUserByName", err) ctx.Handle(500, "GetUserByName", err)
} }
@ -182,7 +182,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
earlyResponseForGoGetMeta(ctx) earlyResponseForGoGetMeta(ctx)
return return
} }
ctx.Handle(404, "GetRepositoryByName", err) ctx.NotFound()
} else { } else {
ctx.Handle(500, "GetRepositoryByName", err) ctx.Handle(500, "GetRepositoryByName", err)
} }
@ -210,7 +210,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
earlyResponseForGoGetMeta(ctx) earlyResponseForGoGetMeta(ctx)
return return
} }
ctx.Handle(404, "no access right", err) ctx.NotFound()
return return
} }
ctx.Data["HasAccess"] = true ctx.Data["HasAccess"] = true
@ -242,7 +242,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
tags, err := ctx.Repo.GitRepo.GetTags() tags, err := ctx.Repo.GitRepo.GetTags()
if err != nil { if err != nil {
ctx.Handle(500, "GetTags", err) ctx.Handle(500, fmt.Sprintf("GetTags '%s'", ctx.Repo.Repository.RepoPath()), err)
return return
} }
ctx.Data["Tags"] = tags ctx.Data["Tags"] = tags
@ -267,7 +267,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
// repo is bare and display enable // repo is bare and display enable
if ctx.Repo.Repository.IsBare { if ctx.Repo.Repository.IsBare {
log.Debug("Bare repository: %s", ctx.Repo.RepoLink) log.Trace("Bare repository: %s", ctx.Repo.RepoLink)
// NOTE: to prevent templating error // NOTE: to prevent templating error
ctx.Data["BranchName"] = "" ctx.Data["BranchName"] = ""
if displayBare { if displayBare {
@ -395,7 +395,7 @@ func RepoRef() macaron.Handler {
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil { if err != nil {
ctx.Handle(404, "GetCommit", nil) ctx.NotFound()
return return
} }
} else { } else {
@ -455,7 +455,7 @@ func RepoRef() macaron.Handler {
func RequireRepoAdmin() macaron.Handler { func RequireRepoAdmin() macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) { if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) {
ctx.Handle(404, ctx.Req.RequestURI, nil) ctx.NotFound()
return return
} }
} }
@ -464,7 +464,7 @@ func RequireRepoAdmin() macaron.Handler {
func RequireRepoWriter() macaron.Handler { func RequireRepoWriter() macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) { if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
ctx.Handle(404, ctx.Req.RequestURI, nil) ctx.NotFound()
return return
} }
} }
@ -474,7 +474,7 @@ func RequireRepoWriter() macaron.Handler {
func GitHookService() macaron.Handler { func GitHookService() macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
if !ctx.User.CanEditGitHook() { if !ctx.User.CanEditGitHook() {
ctx.Handle(404, "GitHookService", nil) ctx.NotFound()
return return
} }
} }

3
modules/cron/cron.go

@ -7,10 +7,11 @@ package cron
import ( import (
"time" "time"
log "gopkg.in/clog.v1"
"github.com/gogits/cron" "github.com/gogits/cron"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

104
modules/log/conn.go

@ -1,104 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"encoding/json"
"io"
"log"
"net"
)
// ConnWriter implements LoggerInterface.
// it writes messages in keep-live tcp connection.
type ConnWriter struct {
lg *log.Logger
innerWriter io.WriteCloser
ReconnectOnMsg bool `json:"reconnectOnMsg"`
Reconnect bool `json:"reconnect"`
Net string `json:"net"`
Addr string `json:"addr"`
Level int `json:"level"`
}
// create new ConnWrite returning as LoggerInterface.
func NewConn() LoggerInterface {
conn := new(ConnWriter)
conn.Level = TRACE
return conn
}
// init connection writer with json config.
// json config only need key "level".
func (cw *ConnWriter) Init(jsonconfig string) error {
return json.Unmarshal([]byte(jsonconfig), cw)
}
// write message in connection.
// if connection is down, try to re-connect.
func (cw *ConnWriter) WriteMsg(msg string, skip, level int) error {
if cw.Level > level {
return nil
}
if cw.neddedConnectOnMsg() {
if err := cw.connect(); err != nil {
return err
}
}
if cw.ReconnectOnMsg {
defer cw.innerWriter.Close()
}
cw.lg.Println(msg)
return nil
}
func (_ *ConnWriter) Flush() {
}
// destroy connection writer and close tcp listener.
func (cw *ConnWriter) Destroy() {
if cw.innerWriter == nil {
return
}
cw.innerWriter.Close()
}
func (cw *ConnWriter) connect() error {
if cw.innerWriter != nil {
cw.innerWriter.Close()
cw.innerWriter = nil
}
conn, err := net.Dial(cw.Net, cw.Addr)
if err != nil {
return err
}
if tcpConn, ok := conn.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
}
cw.innerWriter = conn
cw.lg = log.New(conn, "", log.Ldate|log.Ltime)
return nil
}
func (cw *ConnWriter) neddedConnectOnMsg() bool {
if cw.Reconnect {
cw.Reconnect = false
return true
}
if cw.innerWriter == nil {
return true
}
return cw.ReconnectOnMsg
}
func init() {
Register("conn", NewConn)
}

73
modules/log/console.go

@ -1,73 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"encoding/json"
"log"
"os"
"runtime"
)
type Brush func(string) string
func NewBrush(color string) Brush {
pre := "\033["
reset := "\033[0m"
return func(text string) string {
return pre + color + "m" + text + reset
}
}
var colors = []Brush{
NewBrush("1;36"), // Trace cyan
NewBrush("1;34"), // Debug blue
NewBrush("1;32"), // Info green
NewBrush("1;33"), // Warn yellow
NewBrush("1;31"), // Error red
NewBrush("1;35"), // Critical purple
NewBrush("1;31"), // Fatal red
}
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
type ConsoleWriter struct {
lg *log.Logger
Level int `json:"level"`
}
// create ConsoleWriter returning as LoggerInterface.
func NewConsole() LoggerInterface {
return &ConsoleWriter{
lg: log.New(os.Stdout, "", log.Ldate|log.Ltime),
Level: TRACE,
}
}
func (cw *ConsoleWriter) Init(config string) error {
return json.Unmarshal([]byte(config), cw)
}
func (cw *ConsoleWriter) WriteMsg(msg string, skip, level int) error {
if cw.Level > level {
return nil
}
if runtime.GOOS == "windows" {
cw.lg.Println(msg)
} else {
cw.lg.Println(colors[level](msg))
}
return nil
}
func (_ *ConsoleWriter) Flush() {
}
func (_ *ConsoleWriter) Destroy() {
}
func init() {
Register("console", NewConsole)
}

243
modules/log/file.go

@ -1,243 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
// FileLogWriter implements LoggerInterface.
// It writes messages by lines limit, file size limit, or time frequency.
type FileLogWriter struct {
*log.Logger
mw *MuxWriter
// The opened file
Filename string `json:"filename"`
Maxlines int `json:"maxlines"`
maxlines_curlines int
// Rotate at size
Maxsize int `json:"maxsize"`
maxsize_cursize int
// Rotate daily
Daily bool `json:"daily"`
Maxdays int64 `json:"maxdays"`
daily_opendate int
Rotate bool `json:"rotate"`
startLock sync.Mutex // Only one log can write to the file
Level int `json:"level"`
}
// an *os.File writer with locker.
type MuxWriter struct {
sync.Mutex
fd *os.File
}
// write to os.File.
func (l *MuxWriter) Write(b []byte) (int, error) {
l.Lock()
defer l.Unlock()
return l.fd.Write(b)
}
// set os.File in writer.
func (l *MuxWriter) SetFd(fd *os.File) {
if l.fd != nil {
l.fd.Close()
}
l.fd = fd
}
// create a FileLogWriter returning as LoggerInterface.
func NewFileWriter() LoggerInterface {
w := &FileLogWriter{
Filename: "",
Maxlines: 1000000,
Maxsize: 1 << 28, //256 MB
Daily: true,
Maxdays: 7,
Rotate: true,
Level: TRACE,
}
// use MuxWriter instead direct use os.File for lock write when rotate
w.mw = new(MuxWriter)
// set MuxWriter as Logger's io.Writer
w.Logger = log.New(w.mw, "", log.Ldate|log.Ltime)
return w
}
// Init file logger with json config.
// config like:
// {
// "filename":"log/gogs.log",
// "maxlines":10000,
// "maxsize":1<<30,
// "daily":true,
// "maxdays":15,
// "rotate":true
// }
func (w *FileLogWriter) Init(config string) error {
if err := json.Unmarshal([]byte(config), w); err != nil {
return err
}
if len(w.Filename) == 0 {
return errors.New("config must have filename")
}
return w.StartLogger()
}
// start file logger. create log file and set to locker-inside file writer.
func (w *FileLogWriter) StartLogger() error {
fd, err := w.createLogFile()
if err != nil {
return err
}
w.mw.SetFd(fd)
if err = w.initFd(); err != nil {
return err
}
return nil
}
func (w *FileLogWriter) docheck(size int) {
w.startLock.Lock()
defer w.startLock.Unlock()
if w.Rotate && ((w.Maxlines > 0 && w.maxlines_curlines >= w.Maxlines) ||
(w.Maxsize > 0 && w.maxsize_cursize >= w.Maxsize) ||
(w.Daily && time.Now().Day() != w.daily_opendate)) {
if err := w.DoRotate(); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
return
}
}
w.maxlines_curlines++
w.maxsize_cursize += size
}
// write logger message into file.
func (w *FileLogWriter) WriteMsg(msg string, skip, level int) error {
if level < w.Level {
return nil
}
n := 24 + len(msg) // 24 stand for the length "2013/06/23 21:00:22 [T] "
w.docheck(n)
w.Logger.Println(msg)
return nil
}
func (w *FileLogWriter) createLogFile() (*os.File, error) {
// Open the log file
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
}
func (w *FileLogWriter) initFd() error {
fd := w.mw.fd
finfo, err := fd.Stat()
if err != nil {
return fmt.Errorf("get stat: %s\n", err)
}
w.maxsize_cursize = int(finfo.Size())
w.daily_opendate = time.Now().Day()
if finfo.Size() > 0 {
content, err := ioutil.ReadFile(w.Filename)
if err != nil {
return err
}
w.maxlines_curlines = len(strings.Split(string(content), "\n"))
} else {
w.maxlines_curlines = 0
}
return nil
}
// DoRotate means it need to write file in new file.
// new file name like xx.log.2013-01-01.2
func (w *FileLogWriter) DoRotate() error {
_, err := os.Lstat(w.Filename)
if err == nil { // file exists
// Find the next available number
num := 1
fname := ""
for ; err == nil && num <= 999; num++ {
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num)
_, err = os.Lstat(fname)
}
// return error if the last file checked still existed
if err == nil {
return fmt.Errorf("rotate: cannot find free log number to rename %s\n", w.Filename)
}
// block Logger's io.Writer
w.mw.Lock()
defer w.mw.Unlock()
fd := w.mw.fd
fd.Close()
// close fd before rename
// Rename the file to its newfound home
if err = os.Rename(w.Filename, fname); err != nil {
return fmt.Errorf("Rotate: %s\n", err)
}
// re-start logger
if err = w.StartLogger(); err != nil {
return fmt.Errorf("Rotate StartLogger: %s\n", err)
}
go w.deleteOldLog()
}
return nil
}
func (w *FileLogWriter) deleteOldLog() {
dir := filepath.Dir(w.Filename)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
defer func() {
if r := recover(); r != nil {
returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r)
}
}()
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
os.Remove(path)
}
}
return returnErr
})
}
// destroy file logger, close file writer.
func (w *FileLogWriter) Destroy() {
w.mw.fd.Close()
}
// flush file logger.
// there are no buffering messages in file logger in memory.
// flush file means sync file from disk.
func (w *FileLogWriter) Flush() {
w.mw.fd.Sync()
}
func init() {
Register("file", NewFileWriter)
}

312
modules/log/log.go

@ -1,312 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"sync"
)
var (
loggers []*Logger
GitLogger *Logger
)
func NewLogger(bufLen int64, mode, config string) {
logger := newLogger(bufLen)
isExist := false
for i, l := range loggers {
if l.adapter == mode {
isExist = true
loggers[i] = logger
}
}
if !isExist {
loggers = append(loggers, logger)
}
if err := logger.SetLogger(mode, config); err != nil {
Fatal(2, "Fail to set logger (%s): %v", mode, err)
}
}
// FIXME: use same log level as other loggers.
func NewGitLogger(logPath string) {
os.MkdirAll(path.Dir(logPath), os.ModePerm)
GitLogger = newLogger(0)
GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath))
}
func Trace(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Trace(format, v...)
}
}
func Debug(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Debug(format, v...)
}
}
func Info(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Info(format, v...)
}
}
func Warn(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Warn(format, v...)
}
}
func Error(skip int, format string, v ...interface{}) {
for _, logger := range loggers {
logger.Error(skip, format, v...)
}
}
func Critical(skip int, format string, v ...interface{}) {
for _, logger := range loggers {
logger.Critical(skip, format, v...)
}
}
func Fatal(skip int, format string, v ...interface{}) {
Error(skip, format, v...)
for _, l := range loggers {
l.Close()
}
os.Exit(1)
}
func Close() {
for _, l := range loggers {
l.Close()
}
}
// .___ __ _____
// | | _____/ |_ ____________/ ____\____ ____ ____
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/
// |___|___| /__| \___ >__| |__| (____ /\___ >___ >
// \/ \/ \/ \/ \/
type LogLevel int
const (
TRACE = iota
DEBUG
INFO
WARN
ERROR
CRITICAL
FATAL
)
// LoggerInterface represents behaviors of a logger provider.
type LoggerInterface interface {
Init(config string) error
WriteMsg(msg string, skip, level int) error
Destroy()
Flush()
}
type loggerType func() LoggerInterface
var adapters = make(map[string]loggerType)
// Register registers given logger provider to adapters.
func Register(name string, log loggerType) {
if log == nil {
panic("log: register provider is nil")
}
if _, dup := adapters[name]; dup {
panic("log: register called twice for provider \"" + name + "\"")
}
adapters[name] = log
}
type logMsg struct {
skip, level int
msg string
}
// Logger is default logger in beego application.
// it can contain several providers and log message into all providers.
type Logger struct {
adapter string
lock sync.Mutex
level int
msg chan *logMsg
outputs map[string]LoggerInterface
quit chan bool
}
// newLogger initializes and returns a new logger.
func newLogger(buffer int64) *Logger {
l := &Logger{
msg: make(chan *logMsg, buffer),
outputs: make(map[string]LoggerInterface),
quit: make(chan bool),
}
go l.StartLogger()
return l
}
// SetLogger sets new logger instance with given logger adapter and config.
func (l *Logger) SetLogger(adapter string, config string) error {
l.lock.Lock()
defer l.lock.Unlock()
if log, ok := adapters[adapter]; ok {
lg := log()
if err := lg.Init(config); err != nil {
return err
}
l.outputs[adapter] = lg
l.adapter = adapter
} else {
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
}
return nil
}
// DelLogger removes a logger adapter instance.
func (l *Logger) DelLogger(adapter string) error {
l.lock.Lock()
defer l.lock.Unlock()
if lg, ok := l.outputs[adapter]; ok {
lg.Destroy()
delete(l.outputs, adapter)
} else {
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
}
return nil
}
func (l *Logger) writerMsg(skip, level int, msg string) error {
if l.level > level {
return nil
}
lm := &logMsg{
skip: skip,
level: level,
}
// Only error information needs locate position for debugging.
if lm.level >= ERROR {
pc, file, line, ok := runtime.Caller(skip)
if ok {
// Get caller function name.
fn := runtime.FuncForPC(pc)
var fnName string
if fn == nil {
fnName = "?()"
} else {
fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
}
fileName := file
if len(fileName) > 20 {
fileName = "..." + fileName[len(fileName)-20:]
}
lm.msg = fmt.Sprintf("[%s:%d %s] %s", fileName, line, fnName, msg)
} else {
lm.msg = msg
}
} else {
lm.msg = msg
}
l.msg <- lm
return nil
}
// StartLogger starts logger chan reading.
func (l *Logger) StartLogger() {
for {
select {
case bm := <-l.msg:
for _, l := range l.outputs {
if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
fmt.Println("ERROR, unable to WriteMsg:", err)
}
}
case <-l.quit:
return
}
}
}
// Flush flushs all chan data.
func (l *Logger) Flush() {
for _, l := range l.outputs {
l.Flush()
}
}
// Close closes logger, flush all chan data and destroy all adapter instances.
func (l *Logger) Close() {
l.quit <- true
for {
if len(l.msg) > 0 {
bm := <-l.msg
for _, l := range l.outputs {
if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
fmt.Println("ERROR, unable to WriteMsg:", err)
}
}
} else {
break
}
}
for _, l := range l.outputs {
l.Flush()
l.Destroy()
}
}
func (l *Logger) Trace(format string, v ...interface{}) {
msg := fmt.Sprintf("[T] "+format, v...)
l.writerMsg(0, TRACE, msg)
}
func (l *Logger) Debug(format string, v ...interface{}) {
msg := fmt.Sprintf("[D] "+format, v...)
l.writerMsg(0, DEBUG, msg)
}
func (l *Logger) Info(format string, v ...interface{}) {
msg := fmt.Sprintf("[I] "+format, v...)
l.writerMsg(0, INFO, msg)
}
func (l *Logger) Warn(format string, v ...interface{}) {
msg := fmt.Sprintf("[W] "+format, v...)
l.writerMsg(0, WARN, msg)
}
func (l *Logger) Error(skip int, format string, v ...interface{}) {
msg := fmt.Sprintf("[E] "+format, v...)
l.writerMsg(skip, ERROR, msg)
}
func (l *Logger) Critical(skip int, format string, v ...interface{}) {
msg := fmt.Sprintf("[C] "+format, v...)
l.writerMsg(skip, CRITICAL, msg)
}
func (l *Logger) Fatal(skip int, format string, v ...interface{}) {
msg := fmt.Sprintf("[F] "+format, v...)
l.writerMsg(skip, FATAL, msg)
l.Close()
os.Exit(1)
}

87
modules/log/smtp.go

@ -1,87 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"encoding/json"
"fmt"
"net/smtp"
"strings"
"time"
)
const (
subjectPhrase = "Diagnostic message from server"
)
// smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server.
type SmtpWriter struct {
Username string `json:"Username"`
Password string `json:"password"`
Host string `json:"Host"`
Subject string `json:"subject"`
RecipientAddresses []string `json:"sendTos"`
Level int `json:"level"`
}
// create smtp writer.
func NewSmtpWriter() LoggerInterface {
return &SmtpWriter{Level: TRACE}
}
// init smtp writer with json config.
// config like:
// {
// "Username":"example@gmail.com",
// "password:"password",
// "host":"smtp.gmail.com:465",
// "subject":"email title",
// "sendTos":["email1","email2"],
// "level":LevelError
// }
func (sw *SmtpWriter) Init(jsonconfig string) error {
return json.Unmarshal([]byte(jsonconfig), sw)
}
// write message in smtp writer.
// it will send an email with subject and only this message.
func (s *SmtpWriter) WriteMsg(msg string, skip, level int) error {
if level < s.Level {
return nil
}
hp := strings.Split(s.Host, ":")
// Set up authentication information.
auth := smtp.PlainAuth(
"",
s.Username,
s.Password,
hp[0],
)
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
content_type := "Content-Type: text/plain" + "; charset=UTF-8"
mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.Username + "<" + s.Username +
">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg)
return smtp.SendMail(
s.Host,
auth,
s.Username,
s.RecipientAddresses,
mailmsg,
)
}
func (_ *SmtpWriter) Flush() {
}
func (_ *SmtpWriter) Destroy() {
}
func init() {
Register("smtp", NewSmtpWriter)
}

2
modules/mailer/mail.go

@ -8,11 +8,11 @@ import (
"fmt" "fmt"
"html/template" "html/template"
log "gopkg.in/clog.v1"
"gopkg.in/gomail.v2" "gopkg.in/gomail.v2"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

2
modules/mailer/mailer.go

@ -15,9 +15,9 @@ import (
"time" "time"
"github.com/jaytaylor/html2text" "github.com/jaytaylor/html2text"
log "gopkg.in/clog.v1"
"gopkg.in/gomail.v2" "gopkg.in/gomail.v2"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

2
modules/markdown/markdown.go

@ -43,7 +43,7 @@ func BuildSanitizer() {
Sanitizer.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) Sanitizer.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
} }
var validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`) var validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://|^mailto:`)
// isLink reports whether link fits valid format. // isLink reports whether link fits valid format.
func isLink(link []byte) bool { func isLink(link []byte) bool {

2
modules/process/manager.go

@ -11,7 +11,7 @@ import (
"os/exec" "os/exec"
"time" "time"
"github.com/gogits/gogs/modules/log" log "gopkg.in/clog.v1"
) )
var ( var (

198
modules/setting/setting.go

@ -5,7 +5,6 @@
package setting package setting
import ( import (
"fmt"
"net/mail" "net/mail"
"net/url" "net/url"
"os" "os"
@ -22,12 +21,12 @@ import (
_ "github.com/go-macaron/cache/redis" _ "github.com/go-macaron/cache/redis"
"github.com/go-macaron/session" "github.com/go-macaron/session"
_ "github.com/go-macaron/session/redis" _ "github.com/go-macaron/session/redis"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/gogits/go-libravatar" "github.com/gogits/go-libravatar"
"github.com/gogits/gogs/modules/bindata" "github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/user" "github.com/gogits/gogs/modules/user"
) )
@ -86,6 +85,7 @@ var (
ListenHost string `ini:"SSH_LISTEN_HOST"` ListenHost string `ini:"SSH_LISTEN_HOST"`
ListenPort int `ini:"SSH_LISTEN_PORT"` ListenPort int `ini:"SSH_LISTEN_PORT"`
RootPath string `ini:"SSH_ROOT_PATH"` RootPath string `ini:"SSH_ROOT_PATH"`
ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
KeyTestPath string `ini:"SSH_KEY_TEST_PATH"` KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
KeygenPath string `ini:"SSH_KEYGEN_PATH"` KeygenPath string `ini:"SSH_KEYGEN_PATH"`
MinimumKeySizeCheck bool `ini:"-"` MinimumKeySizeCheck bool `ini:"-"`
@ -98,13 +98,14 @@ var (
LogInRememberDays int LogInRememberDays int
CookieUserName string CookieUserName string
CookieRememberName string CookieRememberName string
CookieSecure bool
ReverseProxyAuthUser string ReverseProxyAuthUser string
// Database settings // Database settings
UseSQLite3 bool UseSQLite3 bool
UseMySQL bool UseMySQL bool
UsePostgreSQL bool UsePostgreSQL bool
UseTiDB bool UseMSSQL bool
// Webhook settings // Webhook settings
Webhook struct { Webhook struct {
@ -144,25 +145,6 @@ var (
RepoRootPath string RepoRootPath string
ScriptType string ScriptType string
// UI settings
UI struct {
ExplorePagingNum int
IssuePagingNum int
FeedMaxCommitNum int
ThemeColorMetaTag string
MaxDisplayFileSize int64
Admin struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
} `ini:"ui.admin"`
User struct {
RepoPagingNum int
} `ini:"ui.user"`
}
// Markdown sttings // Markdown sttings
Markdown struct { Markdown struct {
EnableHardLineBreak bool EnableHardLineBreak bool
@ -170,6 +152,11 @@ var (
FileExtensions []string FileExtensions []string
} }
// Admin settings
Admin struct {
DisableRegularOrgCreation bool
}
// Picture settings // Picture settings
AvatarUploadPath string AvatarUploadPath string
GravatarSource string GravatarSource string
@ -180,7 +167,7 @@ var (
// Log settings // Log settings
LogRootPath string LogRootPath string
LogModes []string LogModes []string
LogConfigs []string LogConfigs []interface{}
// Attachment settings // Attachment settings
AttachmentPath string AttachmentPath string
@ -224,6 +211,7 @@ var (
// Git settings // Git settings
Git struct { Git struct {
Version string `ini:"-"`
DisableDiffHighlight bool DisableDiffHighlight bool
MaxGitDiffLines int MaxGitDiffLines int
MaxGitDiffLineCharacters int MaxGitDiffLineCharacters int
@ -248,6 +236,25 @@ var (
MaxResponseItems int MaxResponseItems int
} }
// UI settings
UI struct {
ExplorePagingNum int
IssuePagingNum int
FeedMaxCommitNum int
ThemeColorMetaTag string
MaxDisplayFileSize int64
Admin struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
} `ini:"ui.admin"`
User struct {
RepoPagingNum int
} `ini:"ui.user"`
}
// I18n settings // I18n settings
Langs, Names []string Langs, Names []string
dateLangs map[string]string dateLangs map[string]string
@ -290,11 +297,11 @@ func execPath() (string, error) {
func init() { func init() {
IsWindows = runtime.GOOS == "windows" IsWindows = runtime.GOOS == "windows"
log.NewLogger(0, "console", `{"level": 0}`) log.New(log.CONSOLE, log.ConsoleConfig{})
var err error var err error
if AppPath, err = execPath(); err != nil { if AppPath, err = execPath(); err != nil {
log.Fatal(4, "fail to get app path: %v\n", err) log.Fatal(4, "Fail to get app path: %v\n", err)
} }
// Note: we don't use path.Dir here because it does not handle case // Note: we don't use path.Dir here because it does not handle case
@ -426,6 +433,7 @@ func NewContext() {
} }
SSH.RootPath = path.Join(homeDir, ".ssh") SSH.RootPath = path.Join(homeDir, ".ssh")
SSH.ServerCiphers = sec.Key("SSH_SERVER_CIPHERS").Strings(",")
SSH.KeyTestPath = os.TempDir() SSH.KeyTestPath = os.TempDir()
if err = Cfg.Section("server").MapTo(&SSH); err != nil { if err = Cfg.Section("server").MapTo(&SSH); err != nil {
log.Fatal(4, "Fail to map SSH settings: %v", err) log.Fatal(4, "Fail to map SSH settings: %v", err)
@ -458,6 +466,7 @@ func NewContext() {
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt() LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
CookieUserName = sec.Key("COOKIE_USERNAME").String() CookieUserName = sec.Key("COOKIE_USERNAME").String()
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String() CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
sec = Cfg.Section("attachment") sec = Cfg.Section("attachment")
@ -563,10 +572,10 @@ func NewContext() {
if err = Cfg.Section("http").MapTo(&HTTP); err != nil { if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
log.Fatal(4, "Fail to map HTTP settings: %v", err) log.Fatal(4, "Fail to map HTTP settings: %v", err)
} else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
log.Fatal(4, "Fail to map UI settings: %v", err)
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil { } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
log.Fatal(4, "Fail to map Markdown settings: %v", err) log.Fatal(4, "Fail to map Markdown settings: %v", err)
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
log.Fatal(4, "Fail to map Admin settings: %v", err)
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil { } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
log.Fatal(4, "Fail to map Cron settings: %v", err) log.Fatal(4, "Fail to map Cron settings: %v", err)
} else if err = Cfg.Section("git").MapTo(&Git); err != nil { } else if err = Cfg.Section("git").MapTo(&Git); err != nil {
@ -575,6 +584,8 @@ func NewContext() {
log.Fatal(4, "Fail to map Mirror settings: %v", err) log.Fatal(4, "Fail to map Mirror settings: %v", err)
} else if err = Cfg.Section("api").MapTo(&API); err != nil { } else if err = Cfg.Section("api").MapTo(&API); err != nil {
log.Fatal(4, "Fail to map API settings: %v", err) log.Fatal(4, "Fail to map API settings: %v", err)
} else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
log.Fatal(4, "Fail to map UI settings: %v", err)
} }
if Mirror.DefaultInterval <= 0 { if Mirror.DefaultInterval <= 0 {
@ -617,82 +628,87 @@ func newService() {
Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
} }
var logLevels = map[string]string{
"Trace": "0",
"Debug": "1",
"Info": "2",
"Warn": "3",
"Error": "4",
"Critical": "5",
}
func newLogService() { func newLogService() {
log.Info("%s %s", AppName, AppVer)
if len(BuildTime) > 0 { if len(BuildTime) > 0 {
log.Info("Build Time: %s", BuildTime) log.Trace("Build Time: %s", BuildTime)
log.Info("Build Git Hash: %s", BuildGitHash) log.Trace("Build Git Hash: %s", BuildGitHash)
} }
// Get and check log mode. // Because we always create a console logger as primary logger before all settings are loaded,
// thus if user doesn't set console logger, we should remove it after other loggers are created.
hasConsole := false
// Get and check log modes.
LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",") LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
LogConfigs = make([]string, len(LogModes)) LogConfigs = make([]interface{}, len(LogModes))
levelNames := map[string]log.LEVEL{
"trace": log.TRACE,
"info": log.INFO,
"warn": log.WARN,
"error": log.ERROR,
"fatal": log.FATAL,
}
for i, mode := range LogModes { for i, mode := range LogModes {
mode = strings.TrimSpace(mode) mode = strings.ToLower(strings.TrimSpace(mode))
sec, err := Cfg.GetSection("log." + mode) sec, err := Cfg.GetSection("log." + mode)
if err != nil { if err != nil {
log.Fatal(4, "Unknown log mode: %s", mode) log.Fatal(4, "Unknown logger mode: %s", mode)
} }
validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"} validLevels := []string{"trace", "info", "warn", "error", "fatal"}
// Log level. name := Cfg.Section("log." + mode).Key("LEVEL").Validate(func(v string) string {
levelName := Cfg.Section("log."+mode).Key("LEVEL").In( v = strings.ToLower(v)
Cfg.Section("log").Key("LEVEL").In("Trace", validLevels), if com.IsSliceContainsStr(validLevels, v) {
validLevels) return v
level, ok := logLevels[levelName]
if !ok {
log.Fatal(4, "Unknown log level: %s", levelName)
} }
return "trace"
})
level := levelNames[name]
// Generate log configuration. // Generate log configuration.
switch mode { switch log.MODE(mode) {
case "console": case log.CONSOLE:
LogConfigs[i] = fmt.Sprintf(`{"level":%s}`, level) hasConsole = true
case "file": LogConfigs[i] = log.ConsoleConfig{
logPath := sec.Key("FILE_NAME").MustString(path.Join(LogRootPath, "gogs.log")) Level: level,
BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
}
case log.FILE:
logPath := path.Join(LogRootPath, "gogs.log")
if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil { if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
panic(err.Error()) log.Fatal(4, "Fail to create log directory '%s': %v", path.Dir(logPath), err)
} }
LogConfigs[i] = fmt.Sprintf( LogConfigs[i] = log.FileConfig{
`{"level":%s,"filename":"%s","rotate":%v,"maxlines":%d,"maxsize":%d,"daily":%v,"maxdays":%d}`, level, Level: level,
logPath, BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
sec.Key("LOG_ROTATE").MustBool(true), Filename: logPath,
sec.Key("MAX_LINES").MustInt(1000000), FileRotationConfig: log.FileRotationConfig{
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)), Rotate: sec.Key("LOG_ROTATE").MustBool(true),
sec.Key("DAILY_ROTATE").MustBool(true), Daily: sec.Key("DAILY_ROTATE").MustBool(true),
sec.Key("MAX_DAYS").MustInt(7)) MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
case "conn": MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":"%s","addr":"%s"}`, level, MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
sec.Key("RECONNECT_ON_MSG").MustBool(), },
sec.Key("RECONNECT").MustBool(), }
sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
sec.Key("ADDR").MustString(":7020")) case log.SLACK:
case "smtp": LogConfigs[i] = log.SlackConfig{
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":["%s"],"subject":"%s"}`, level, Level: level,
sec.Key("USER").MustString("example@example.com"), BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
sec.Key("PASSWD").MustString("******"), URL: sec.Key("URL").String(),
sec.Key("HOST").MustString("127.0.0.1:25"), }
strings.Replace(sec.Key("RECEIVERS").MustString(""), ",", `","`, -1), }
sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
case "database": log.New(log.MODE(mode), LogConfigs[i])
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level, log.Trace("Log Mode: %s (%s)", strings.Title(mode), strings.Title(name))
sec.Key("DRIVER").String(), }
sec.Key("CONN").String())
} // Make sure everyone gets version info printed.
log.Info("%s %s", AppName, AppVer)
log.NewLogger(Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000), mode, LogConfigs[i]) if !hasConsole {
log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName) log.Delete(log.CONSOLE)
} }
} }
@ -806,6 +822,10 @@ func newWebhookService() {
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
} }
func NewService() {
newService()
}
func NewServices() { func NewServices() {
newService() newService()
newLogService() newLogService()

9
modules/ssh/ssh.go

@ -16,9 +16,9 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
@ -148,8 +148,11 @@ func listen(config *ssh.ServerConfig, host string, port int) {
} }
// Listen starts a SSH server listens on given port. // Listen starts a SSH server listens on given port.
func Listen(host string, port int) { func Listen(host string, port int, ciphers []string) {
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
Config: ssh.Config{
Ciphers: ciphers,
},
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))) pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
if err != nil { if err != nil {
@ -163,7 +166,7 @@ func Listen(host string, port int) {
keyPath := filepath.Join(setting.AppDataPath, "ssh/gogs.rsa") keyPath := filepath.Join(setting.AppDataPath, "ssh/gogs.rsa")
if !com.IsExist(keyPath) { if !com.IsExist(keyPath) {
os.MkdirAll(filepath.Dir(keyPath), os.ModePerm) os.MkdirAll(filepath.Dir(keyPath), os.ModePerm)
_, stderr, err := com.ExecCmd("ssh-keygen", "-f", keyPath, "-t", "rsa", "-N", "") _, stderr, err := com.ExecCmd(setting.SSH.KeygenPath, "-f", keyPath, "-t", "rsa", "-N", "")
if err != nil { if err != nil {
panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr)) panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr))
} }

2
modules/template/template.go

@ -17,11 +17,11 @@ import (
"golang.org/x/net/html/charset" "golang.org/x/net/html/charset"
"golang.org/x/text/transform" "golang.org/x/text/transform"
log "gopkg.in/clog.v1"
"gopkg.in/editorconfig/editorconfig-core-go.v1" "gopkg.in/editorconfig/editorconfig-core-go.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/markdown"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )

76
public/assets/librejs/librejs.html

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript license information</title>
</head>
<body>
<table id="jslicense-labels1">
<tr>
<td><a href="/js/libs/jquery.are-you-sure.js">jquery.are-you-sure.js</a></td>
<td>
<a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a>
<br>
<a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU-GPL-2.0-or-later</a>
</td>
<td><a href="/js/libs/jquery.are-you-sure.js">jquery.are-you-sure.js</a></td>
</tr>
<tr>
<td><a href="/js/semantic-2.2.7.min.js">semantic-2.2.1.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/Semantic-Org/Semantic-UI/archive/2.2.1.tar.gz">semantic-UI-2.2.1.tar.gz</a></td>
</tr>
<tr>
<td><a href="/js/gogs.js">gogs.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="/js/gogs.js">gogs.js</a></td>
</tr>
<tr>
<td><a href="/js/libs/clipboard-1.5.9.min.js">clipboard-1.5.9.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/zenorocha/clipboard.js/archive/v1.5.9.tar.gz">clipboard-1.5.9.tar.gz</a></td>
</tr>
<tr>
<td><a href="/js/libs/emojify-1.1.0.min.js">emojify-1.1.0.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/Ranks/emojify.js/archive/1.1.0.tar.gz">emojify-1.1.0.tar.gz</a></td>
</tr>
<tr>
<td><a href="/plugins/dropzone-4.2.0/dropzone.js">dropzone.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="/plugins/dropzone-4.2.0/dropzone.js">dropzone.js</a></td>
</tr>
<tr>
<td><a href="/plugins/highlight-9.6.0/highlight.pack.js">highlight.pack.js</a></td>
<td><a href="https://github.com/isagalaev/highlight.js/blob/master/LICENSE">BSD 3 Clause</a></td>
<td><a href="https://github.com/isagalaev/highlight.js/archive/9.6.0.tar.gz">highlight.js-9.6.0.tar.gz</a></td>
</tr>
<tr>
<td><a href="/plugins/jquery.datetimepicker-2.4.5/jquery.datetimepicker.js">jquery.datetimepicker.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="/plugins/jquery.datetimepicker-2.4.5/jquery.datetimepicker.js">jquery.datetimepicker.js</a></td>
</tr>
<tr>
<td><a href="/plugins/jquery.minicolors-2.2.3/jquery.minicolors.min.js">jquery.minicolors.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/claviska/jquery-minicolors/archive/2.2.3.tar.gz">jquery.minicolors-2.2.3.tar.gz</a></td>
</tr>
<tr>
<td><a href="/plugins/simplemde-1.10.1/simplemde.min.js">simplemde.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://github.com/NextStepWebs/simplemde-markdown-editor/archive/1.10.1.tar.gz">simplemde-markdown-editor-1.10.1.tar.gz</a></td>
</tr>
<tr>
<td><a href="/plugins/marked-0.3.6/marked.min.js">marked.min.js</a></td>
<td><a href="https://github.com/chjj/marked/blob/master/LICENSE">Expat</a></td>
<td><a href="https://github.com/chjj/marked/archive/v0.3.6.tar.gz">marked-0.3.6.tar.gz</a></td>
</tr>
<tr>
<td><a href="/plugins/notebookjs-0.2.6/notebook.min.js">notebook.min.js</a></td>
<td><a href="https://github.com/jsvine/notebookjs/blob/master/LICENSE.txt">Expat</a></td>
<td><a href="https://github.com/jsvine/notebookjs/archive/v0.2.6.tar.gz">notebookjs-0.2.6.tar.gz</a></td>
</tr>
</table>
</body>
</html>

88
public/css/gogs.css

@ -845,6 +845,7 @@ footer .ui.language .menu {
} }
.home .logo { .home .logo {
max-width: 220px; max-width: 220px;
margin-bottom: 20px;
} }
.home .hero h1, .home .hero h1,
.home .hero h2 { .home .hero h2 {
@ -1306,6 +1307,93 @@ footer .ui.language .menu {
.repository.file.list #file-content .view-raw img { .repository.file.list #file-content .view-raw img {
margin-bottom: -5px; margin-bottom: -5px;
} }
.repository.file.list #file-content #ipython-notebook {
margin-left: 95px;
padding-top: 1px;
}
.repository.file.list #file-content #ipython-notebook .nb-notebook {
line-height: 1.5;
}
.repository.file.list #file-content #ipython-notebook .nb-stdout,
.repository.file.list #file-content #ipython-notebook .nb-stderr {
white-space: pre-wrap;
margin: 1em 0;
padding: 0.1em 0.5em;
}
.repository.file.list #file-content #ipython-notebook .nb-stderr {
background-color: #FAA;
}
.repository.file.list #file-content #ipython-notebook .nb-cell + .nb-cell {
margin-top: 0.5em;
}
.repository.file.list #file-content #ipython-notebook .nb-cell {
position: relative;
}
.repository.file.list #file-content #ipython-notebook .nb-cell.nb-heading-cell {
margin-top: 0.5em;
}
.repository.file.list #file-content #ipython-notebook .nb-raw-cell {
white-space: pre-wrap;
background-color: #f5f2f0;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
padding: 1em;
margin: .5em 0;
}
.repository.file.list #file-content #ipython-notebook .nb-input:before,
.repository.file.list #file-content #ipython-notebook .nb-output:before {
position: absolute;
font-family: monospace;
color: #999;
left: -7.5em;
width: 7em;
text-align: right;
}
.repository.file.list #file-content #ipython-notebook .nb-input:before {
content: "In [" attr(data-prompt-number) "]:";
}
.repository.file.list #file-content #ipython-notebook .nb-input pre {
background-color: #f7f7f7;
margin-right: 10px;
padding: 5px 10px;
}
.repository.file.list #file-content #ipython-notebook .nb-input pre code {
min-height: 18px;
line-height: 18px;
font-size: 14px;
}
.repository.file.list #file-content #ipython-notebook .nb-output:before {
content: "Out [" attr(data-prompt-number) "]:";
}
.repository.file.list #file-content #ipython-notebook .nb-output pre {
padding: 5px 10px;
font-size: 14px;
}
.repository.file.list #file-content #ipython-notebook .nb-output img {
max-width: 100%;
}
.repository.file.list #file-content #ipython-notebook .nb-output table {
border: 1px solid #000;
border-collapse: collapse;
}
.repository.file.list #file-content #ipython-notebook .nb-output th {
font-weight: bold;
}
.repository.file.list #file-content #ipython-notebook .nb-output th,
.repository.file.list #file-content #ipython-notebook .nb-output td {
border: 1px solid #000;
padding: 0.25em;
text-align: left;
vertical-align: middle;
border-collapse: collapse;
}
.repository.file.list #file-content #ipython-notebook .nb-markdown-cell {
margin-top: 10px;
margin-right: 10px;
padding: 10px;
}
.repository.file.list #file-content #ipython-notebook div[style="max-height:1000px;max-width:1500px;overflow:auto;"] {
max-height: none !important;
}
.repository.file.list #file-content .plain-text { .repository.file.list #file-content .plain-text {
font-size: 14px; font-size: 14px;
padding: 10px 15px; padding: 10px 15px;

BIN
public/img/avatar_default.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 502 KiB

BIN
public/img/favicon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 28 KiB

BIN
public/img/gogs-large-resize.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 81 KiB

BIN
public/img/gogs-lg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 164 KiB

192
public/img/gogs.svg

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg4576"
inkscape:version="0.92.0 r15299"
sodipodi:docname="icon.svg"
enable-background="new"
inkscape:export-filename="favicon.png"
inkscape:export-xdpi="96.000008"
inkscape:export-ydpi="96.000008">
<defs
id="defs4570">
<linearGradient
inkscape:collect="always"
id="linearGradient5777">
<stop
style="stop-color:#dc493c;stop-opacity:1;"
offset="0"
id="stop5773" />
<stop
style="stop-color:#e8887f;stop-opacity:1"
offset="1"
id="stop5775" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath5477">
<path
sodipodi:nodetypes="cccccccccccccccccccccscc"
inkscape:connector-curvature="0"
id="path5479"
d="m 33.86713,243.43265 c -10.880422,-1.1e-4 -19.700791,8.82024 -19.700666,19.70068 -1.25e-4,10.88042 8.820244,19.70077 19.700666,19.70066 6.169379,-0.0143 11.975716,-2.91813 15.688204,-7.84549 l 0.01791,0.0107 0.102743,-0.17755 c 0.918898,-1.23276 1.69033,-2.56885 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01826,-0.18413 0.02739,-0.36903 0.02774,-0.55405 -1.9e-5,-3.17384 -2.572912,-5.74673 -5.746748,-5.74677 -3.173838,4e-5 -5.746734,2.57293 -5.746768,5.74677 3.4e-5,3.17384 2.57293,5.74673 5.746768,5.74677 1.179669,-0.002 2.32995,-0.36815 3.29469,-1.04706 l 7.43758,4.29458 c -2.657252,3.18291 -6.585981,5.02791 -10.73227,5.0401 -7.750976,-4e-5 -14.034355,-6.28343 -14.034391,-14.03439 3.6e-5,-7.75096 6.283415,-14.03435 14.034391,-14.03437 1.644346,0.009 3.274248,0.30783 4.815319,0.88147 0.432941,0.23108 0.919115,0.35231 1.413341,0.35241 1.619414,1.3e-4 2.932237,-1.27253 2.932112,-2.8424 -0.0013,-1.0165 -0.711451,-1.96286 -1.620721,-2.46915 0,0 -0.459666,-0.22667 -0.620453,-0.28907 -2.205641,-0.85587 -4.553725,-1.2854 -6.919582,-1.29957 z"
style="opacity:1;fill:none;fill-opacity:1;stroke:#be3529;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5777"
id="linearGradient5779"
x1="52.65686"
y1="291.88074"
x2="9.1281252"
y2="234.42603"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5777"
id="linearGradient5874"
x1="58.605209"
y1="304.01141"
x2="7.1437502"
y2="224.76874"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4520"
x="-0.0024505704"
width="1.0049011"
y="-0.0023514745"
height="1.0047029">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.038604687"
id="feGaussianBlur4522" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4528"
x="-0.0024479733"
width="1.0048959"
y="-0.0023538708"
height="1.0047077">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.064072276"
id="feGaussianBlur4530" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="44.531899"
inkscape:cy="180.4412"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:showpageshadow="false"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-page="true" />
<metadata
id="metadata4573">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="shadowed"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)"
style="display:inline">
<g
id="g5745">
<path
inkscape:connector-curvature="0"
style="opacity:1;fill:none;fill-opacity:1;stroke:#5b1a14;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4528)"
d="m 27.626438,230.93706 -1.796274,7.39227 a 26.550438,26.550438 0 0 0 -9.959928,5.78561 l -7.2442762,-2.1237 -6.1676142,10.68233 5.4923951,5.24175 a 26.550438,26.550438 0 0 0 -0.6345185,5.68571 26.550438,26.550438 0 0 0 0.6835439,5.83648 l -5.4683514,5.21769 6.1676178,10.68233 7.3006845,-2.14037 a 26.550438,26.550438 0 0 0 9.996944,5.75973 l 1.775923,7.30808 h 12.334305 l 1.796274,-7.39133 a 26.550438,26.550438 0 0 0 9.959946,-5.78561 l 7.244271,2.12277 6.167608,-10.68233 -5.492404,-5.24081 a 26.550438,26.550438 0 0 0 0.634521,-5.68663 26.550438,26.550438 0 0 0 -0.683546,-5.83557 l 5.468366,-5.2186 -6.167627,-10.68235 -7.300689,2.14037 a 26.550438,26.550438 0 0 0 -9.996012,-5.7588 l -1.775923,-7.30902 z"
id="path5311" />
<path
id="circle4730"
d="m 27.626438,230.46936 -1.796274,7.39227 a 26.550438,26.550438 0 0 0 -9.959928,5.78561 l -7.2442762,-2.1237 -6.1676142,10.68233 5.4923951,5.24175 a 26.550438,26.550438 0 0 0 -0.6345185,5.68571 26.550438,26.550438 0 0 0 0.6835439,5.83648 l -5.4683514,5.21769 6.1676178,10.68233 7.3006845,-2.14037 a 26.550438,26.550438 0 0 0 9.996944,5.75973 l 1.775923,7.30808 h 12.334305 l 1.796274,-7.39133 a 26.550438,26.550438 0 0 0 9.959946,-5.78561 l 7.244271,2.12277 6.167608,-10.68233 -5.492404,-5.24081 a 26.550438,26.550438 0 0 0 0.634521,-5.68663 26.550438,26.550438 0 0 0 -0.683546,-5.83557 l 5.468366,-5.2186 -6.167627,-10.68235 -7.300689,2.14037 a 26.550438,26.550438 0 0 0 -9.996012,-5.7588 l -1.775923,-7.30902 z"
style="opacity:1;fill:url(#linearGradient5874);fill-opacity:1;stroke:#be3529;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccccccccccccccccccccscc"
inkscape:connector-curvature="0"
id="circle4744"
d="m 33.867129,243.43265 c -10.880421,-1.1e-4 -19.70079,8.82024 -19.700665,19.70068 -1.25e-4,10.88042 8.820244,19.70077 19.700665,19.70066 6.169381,-0.0143 11.975716,-2.91813 15.688205,-7.84549 l 0.0179,0.0107 0.102741,-0.17755 c 0.9189,-1.23276 1.69033,-2.56885 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01826,-0.18413 0.02739,-0.36903 0.02774,-0.55405 -1.8e-5,-3.17384 -2.572913,-5.74673 -5.746749,-5.74677 -3.173837,4e-5 -5.746732,2.57293 -5.746768,5.74677 3.6e-5,3.17384 2.572931,5.74673 5.746768,5.74677 1.17967,-0.002 2.329951,-0.36815 3.29469,-1.04706 l 7.43758,4.29458 c -2.657252,3.18291 -6.58598,5.02791 -10.73227,5.0401 -7.750975,-4e-5 -14.034354,-6.28343 -14.03439,-14.03439 3.6e-5,-7.75096 6.283415,-14.03435 14.03439,-14.03437 1.644347,0.009 3.27425,0.30783 4.815319,0.88147 0.432942,0.23108 0.919115,0.35231 1.413343,0.35241 1.619414,1.3e-4 2.932235,-1.27253 2.93211,-2.8424 -0.0014,-1.0165 -0.71145,-1.96286 -1.62072,-2.46915 0,0 -0.459665,-0.22667 -0.620452,-0.28907 -2.205643,-0.85587 -4.553726,-1.2854 -6.919583,-1.29957 z"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#7f231c;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4520)"
d="m 33.94898,243.79513 c -10.88042,-1.4e-4 -19.705814,8.97349 -19.700665,19.70068 0.0049,10.72717 8.820244,19.70077 19.700665,19.70066 6.169381,-0.0143 11.976514,-2.94246 15.688205,-7.84549 l 0.0179,0.0107 0.102741,-0.17755 c 0.9187,-1.22666 1.690687,-2.57973 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01795,-0.17465 0.02771,-0.37872 0.02774,-0.55405 -0.0055,-3.00718 -2.572913,-5.74673 -5.746749,-5.74677 -3.173837,4e-5 -5.752196,2.73959 -5.746768,5.74677 0.0055,3.00719 2.572931,5.74674 5.746768,5.74677 1.179664,-0.002 2.330958,-0.39886 3.29469,-1.04706 l 7.43758,4.29458 c -2.654987,3.11383 -6.586003,5.02861 -10.73227,5.0401 -7.750975,-3e-5 -14.026256,-6.5304 -14.03439,-14.03439 -0.0081,-7.50398 6.283415,-14.03434 14.03439,-14.03437 1.644325,0.01 3.27333,0.33588 4.815319,0.88147 0.43305,0.22778 0.918249,0.37874 1.413343,0.35241 1.622253,-0.0865 2.928924,-1.17153 2.93211,-2.8424 7.41e-4,-1.08181 -0.711334,-1.96639 -1.62072,-2.46915 0,0 -0.459602,-0.22859 -0.620452,-0.28907 -2.206511,-0.8294 -4.553766,-1.28416 -6.919583,-1.29957 z"
id="path5473"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccscc"
clip-path="url(#clipPath5477)" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#be3529;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.867129,243.43265 c -10.880421,-1.1e-4 -19.70079,8.82024 -19.700665,19.70068 -1.25e-4,10.88042 8.820244,19.70077 19.700665,19.70066 6.169381,-0.0143 11.975716,-2.91813 15.688205,-7.84549 l 0.0179,0.0107 0.102741,-0.17755 c 0.9189,-1.23276 1.69033,-2.56885 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01826,-0.18413 0.02739,-0.36903 0.02774,-0.55405 -1.8e-5,-3.17384 -2.572913,-5.74673 -5.746749,-5.74677 -3.173837,4e-5 -5.746732,2.57293 -5.746768,5.74677 3.6e-5,3.17384 2.572931,5.74673 5.746768,5.74677 1.17967,-0.002 2.329951,-0.36815 3.29469,-1.04706 l 7.43758,4.29458 c -2.657252,3.18291 -6.58598,5.02791 -10.73227,5.0401 -7.750975,-4e-5 -14.034354,-6.28343 -14.03439,-14.03439 3.6e-5,-7.75096 6.283415,-14.03435 14.03439,-14.03437 1.644347,0.009 3.27425,0.30783 4.815319,0.88147 0.432942,0.23108 0.919115,0.35231 1.413343,0.35241 1.619414,1.3e-4 2.932235,-1.27253 2.93211,-2.8424 -0.0014,-1.0165 -0.71145,-1.96286 -1.62072,-2.46915 0,0 -0.459665,-0.22667 -0.620452,-0.28907 -2.205643,-0.85587 -4.553726,-1.2854 -6.919583,-1.29957 z"
id="path5733"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccscc" />
</g>
</g>
<g
transform="translate(0,-229.26665)"
id="g5771"
inkscape:groupmode="layer"
inkscape:label="plain"
style="display:none">
<g
id="g5769">
<path
inkscape:connector-curvature="0"
style="opacity:1;fill:url(#linearGradient5779);fill-opacity:1;stroke:#be3529;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.626438,230.46936 -1.796274,7.39227 a 26.550438,26.550438 0 0 0 -9.959928,5.78561 l -7.2442762,-2.1237 -6.1676142,10.68233 5.4923951,5.24175 a 26.550438,26.550438 0 0 0 -0.6345185,5.68571 26.550438,26.550438 0 0 0 0.6835439,5.83648 l -5.4683514,5.21769 6.1676178,10.68233 7.3006845,-2.14037 a 26.550438,26.550438 0 0 0 9.996944,5.75973 l 1.775923,7.30808 h 12.334305 l 1.796274,-7.39133 a 26.550438,26.550438 0 0 0 9.959946,-5.78561 l 7.244271,2.12277 6.167608,-10.68233 -5.492404,-5.24081 a 26.550438,26.550438 0 0 0 0.634521,-5.68663 26.550438,26.550438 0 0 0 -0.683546,-5.83557 l 5.468366,-5.2186 -6.167627,-10.68235 -7.300689,2.14037 a 26.550438,26.550438 0 0 0 -9.996012,-5.7588 l -1.775923,-7.30902 z"
id="path5761" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33.867129,243.43265 c -10.880421,-1.1e-4 -19.70079,8.82024 -19.700665,19.70068 -1.25e-4,10.88042 8.820244,19.70077 19.700665,19.70066 6.169381,-0.0143 11.975716,-2.91813 15.688205,-7.84549 l 0.0179,0.0107 0.102741,-0.17755 c 0.9189,-1.23276 1.69033,-2.56885 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01826,-0.18413 0.02739,-0.36903 0.02774,-0.55405 -1.8e-5,-3.17384 -2.572913,-5.74673 -5.746749,-5.74677 -3.173837,4e-5 -5.746732,2.57293 -5.746768,5.74677 3.6e-5,3.17384 2.572931,5.74673 5.746768,5.74677 1.17967,-0.002 2.329951,-0.36815 3.29469,-1.04706 l 7.43758,4.29458 c -2.657252,3.18291 -6.58598,5.02791 -10.73227,5.0401 -7.750975,-4e-5 -14.034354,-6.28343 -14.03439,-14.03439 3.6e-5,-7.75096 6.283415,-14.03435 14.03439,-14.03437 1.644347,0.009 3.27425,0.30783 4.815319,0.88147 0.432942,0.23108 0.919115,0.35231 1.413343,0.35241 1.619414,1.3e-4 2.932235,-1.27253 2.93211,-2.8424 -0.0014,-1.0165 -0.71145,-1.96286 -1.62072,-2.46915 0,0 -0.459665,-0.22667 -0.620452,-0.28907 -2.205643,-0.85587 -4.553726,-1.2854 -6.919583,-1.29957 z"
id="path5763"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccscc" />
<path
sodipodi:nodetypes="cccccccccccccccccccccscc"
inkscape:connector-curvature="0"
id="path5767"
d="m 33.867129,243.43265 c -10.880421,-1.1e-4 -19.70079,8.82024 -19.700665,19.70068 -1.25e-4,10.88042 8.820244,19.70077 19.700665,19.70066 6.169381,-0.0143 11.975716,-2.91813 15.688205,-7.84549 l 0.0179,0.0107 0.102741,-0.17755 c 0.9189,-1.23276 1.69033,-2.56885 2.29852,-3.98101 l -12.387966,-7.1527 c 0.01826,-0.18413 0.02739,-0.36903 0.02774,-0.55405 -1.8e-5,-3.17384 -2.572913,-5.74673 -5.746749,-5.74677 -3.173837,4e-5 -5.746732,2.57293 -5.746768,5.74677 3.6e-5,3.17384 2.572931,5.74673 5.746768,5.74677 1.17967,-0.002 2.329951,-0.36815 3.29469,-1.04706 l 7.43758,4.29458 c -2.657252,3.18291 -6.58598,5.02791 -10.73227,5.0401 -7.750975,-4e-5 -14.034354,-6.28343 -14.03439,-14.03439 3.6e-5,-7.75096 6.283415,-14.03435 14.03439,-14.03437 1.644347,0.009 3.27425,0.30783 4.815319,0.88147 0.432942,0.23108 0.919115,0.35231 1.413343,0.35241 1.619414,1.3e-4 2.932235,-1.27253 2.93211,-2.8424 -0.0014,-1.0165 -0.71145,-1.96286 -1.62072,-2.46915 0,0 -0.459665,-0.22667 -0.620452,-0.28907 -2.205643,-0.85587 -4.553726,-1.2854 -6.919583,-1.29957 z"
style="opacity:1;fill:none;fill-opacity:1;stroke:#be3529;stroke-width:0.66145831;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

23
public/js/gogs.js

@ -228,23 +228,22 @@ function initInstall() {
return; return;
} }
var mysqlDefault = '127.0.0.1:3306'; var dbDefaults = {
var postgresDefault = '127.0.0.1:5432'; "MySQL": "127.0.0.1:3306",
"PostgreSQL": "127.0.0.1:5432",
"MSSQL": "127.0.0.1, 1433"
};
$('#sqlite_settings').hide(); $('#sqlite_settings').hide();
$('#sql_settings').show(); $('#sql_settings').show();
if (dbType === "PostgreSQL") { $('#pgsql_settings').toggle(dbType === "PostgreSQL");
$('#pgsql_settings').show(); $.each(dbDefaults, function(type, defaultHost) {
if ($('#db_host').val() == mysqlDefault) { if ($('#db_host').val() == defaultHost) {
$('#db_host').val(postgresDefault); $('#db_host').val(dbDefaults[dbType]);
} return false;
} else {
$('#pgsql_settings').hide();
if ($('#db_host').val() == postgresDefault) {
$('#db_host').val(mysqlDefault);
}
} }
}); });
});
// TODO: better handling of exclusive relations. // TODO: better handling of exclusive relations.
$('#offline-mode input').change(function () { $('#offline-mode input').change(function () {

1
public/less/_home.less

@ -2,6 +2,7 @@
padding-bottom: @footer-margin * 2; padding-bottom: @footer-margin * 2;
.logo { .logo {
max-width: 220px; max-width: 220px;
margin-bottom: 20px;
} }
.hero { .hero {
h1, h2 { h1, h2 {

105
public/less/_repository.less

@ -251,6 +251,111 @@
} }
} }
#ipython-notebook {
margin-left: 95px;
padding-top: 1px;
.nb-notebook {
line-height: 1.5;
}
.nb-stdout, .nb-stderr {
white-space: pre-wrap;
margin: 1em 0;
padding: 0.1em 0.5em;
}
.nb-stderr {
background-color: #FAA;
}
.nb-cell + .nb-cell {
margin-top: 0.5em;
}
.nb-cell {
position: relative;
&.nb-heading-cell {
margin-top: 0.5em;
}
}
.nb-raw-cell {
white-space: pre-wrap;
background-color: #f5f2f0;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
padding: 1em;
margin: .5em 0;
}
.nb-input:before,
.nb-output:before {
position: absolute;
font-family: monospace;
color: #999;
left: -7.5em;
width: 7em;
text-align: right;
}
.nb-input {
&:before {
content: "In [" attr(data-prompt-number) "]:";
}
pre {
background-color: #f7f7f7;
margin-right: 10px;
padding: 5px 10px;
code {
min-height: 18px;
line-height: 18px;
font-size: 14px;
}
}
}
.nb-output{
&:before {
content: "Out [" attr(data-prompt-number) "]:";
}
pre {
padding: 5px 10px;
font-size: 14px;
}
img {
max-width: 100%;
}
table {
border: 1px solid #000;
border-collapse: collapse;
}
th {
font-weight: bold;
}
th,
td {
border: 1px solid #000;
padding: 0.25em;
text-align: left;
vertical-align: middle;
border-collapse: collapse;
}
}
.nb-markdown-cell {
margin-top: 10px;
margin-right: 10px;
padding: 10px;
}
// Fix pandas dataframe formatting
div[style="max-height:1000px;max-width:1500px;overflow:auto;"] {
max-height: none !important;
}
}
.plain-text { .plain-text {
font-size: 14px; font-size: 14px;
padding: 10px 15px; padding: 10px 15px;

6
public/plugins/marked-0.3.6/marked.min.js vendored

File diff suppressed because one or more lines are too long

1
public/plugins/notebookjs-0.2.6/notebook.min.js vendored

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save