@@ -257,6 +257,12 @@ CONN = | |||
[git] | |||
MAX_GITDIFF_LINES = 10000 | |||
; Arguments for command 'git fsck', e.g.: "--unreachable --tags" | |||
; see more on http://git-scm.com/docs/git-fsck/1.7.5 | |||
FSCK_ARGS = | |||
; Arguments for command 'git gc', e.g.: "--aggressive --auto" | |||
; see more on http://git-scm.com/docs/git-gc/1.7.5 | |||
GC_ARGS = | |||
[i18n] | |||
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL |
@@ -476,6 +476,8 @@ dashboard.delete_inactivate_accounts = Delete all inactive accounts | |||
dashboard.delete_inactivate_accounts_success = All inactivate accounts have been deleted successfully. | |||
dashboard.delete_repo_archives = Delete all repositories archives | |||
dashboard.delete_repo_archives_success = All repositories archives have been deleted successfully. | |||
dashboard.git_gc_repos = Do garbage collection on repositories | |||
dashboard.git_gc_repos_success = All repositories have done garbage collection successfully. | |||
dashboard.server_uptime = Server Uptime | |||
dashboard.current_goroutine = Current Goroutines | |||
dashboard.current_memory_usage = Current Memory Usage |
@@ -17,7 +17,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.5.8.1128 Beta" | |||
const APP_VER = "0.5.8.1130 Beta" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -1140,18 +1140,8 @@ type SearchOption struct { | |||
Private bool | |||
} | |||
// FilterSQLInject tries to prevent SQL injection. | |||
func FilterSQLInject(key string) string { | |||
key = strings.TrimSpace(key) | |||
key = strings.Split(key, " ")[0] | |||
key = strings.Replace(key, ",", "", -1) | |||
return key | |||
} | |||
// SearchRepositoryByName returns given number of repositories whose name contains keyword. | |||
func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) { | |||
// Prevent SQL inject. | |||
opt.Keyword = FilterSQLInject(opt.Keyword) | |||
if len(opt.Keyword) == 0 { | |||
return repos, nil | |||
} | |||
@@ -1183,6 +1173,47 @@ func DeleteRepositoryArchives() error { | |||
}) | |||
} | |||
// GitFsck calls 'git fsck' to check repository health. | |||
func GitFsck() { | |||
args := append([]string{"fsck"}, setting.GitFsckArgs...) | |||
if err := x.Where("id > 0").Iterate(new(Repository), | |||
func(idx int, bean interface{}) error { | |||
repo := bean.(*Repository) | |||
if err := repo.GetOwner(); err != nil { | |||
return err | |||
} | |||
repoPath := RepoPath(repo.Owner.Name, repo.Name) | |||
_, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...) | |||
if err != nil { | |||
desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath) | |||
log.Warn(desc) | |||
if err = CreateRepositoryNotice(desc); err != nil { | |||
log.Error(4, "Fail to add notice: %v", err) | |||
} | |||
} | |||
return nil | |||
}); err != nil { | |||
log.Error(4, "repo.Fsck: %v", err) | |||
} | |||
} | |||
func GitGcRepos() error { | |||
args := append([]string{"gc"}, setting.GitGcArgs...) | |||
return x.Where("id > 0").Iterate(new(Repository), | |||
func(idx int, bean interface{}) error { | |||
repo := bean.(*Repository) | |||
if err := repo.GetOwner(); err != nil { | |||
return err | |||
} | |||
_, stderr, err := process.ExecDir(-1, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", "git", args...) | |||
if err != nil { | |||
return fmt.Errorf("%v: %v", err, stderr) | |||
} | |||
return nil | |||
}) | |||
} | |||
// __ __ __ .__ | |||
// / \ / \_____ _/ |_ ____ | |__ | |||
// \ \/\/ /\__ \\ __\/ ___\| | \ |
@@ -628,7 +628,6 @@ func GetUserByEmail(email string) (*User, error) { | |||
// SearchUserByName returns given number of users whose name contains keyword. | |||
func SearchUserByName(opt SearchOption) (us []*User, err error) { | |||
opt.Keyword = FilterSQLInject(opt.Keyword) | |||
if len(opt.Keyword) == 0 { | |||
return us, nil | |||
} |
@@ -14,8 +14,10 @@ import ( | |||
var c = New() | |||
func NewCronContext() { | |||
models.GitFsck() | |||
c.AddFunc("Update mirrors", "@every 1h", models.MirrorUpdate) | |||
c.AddFunc("Deliver hooks", fmt.Sprintf("@every %dm", setting.WebhookTaskInterval), models.DeliverHooks) | |||
c.AddFunc("Repository health check", "@every 1h", models.GitFsck) | |||
c.Start() | |||
} | |||
@@ -109,6 +109,8 @@ var ( | |||
// Git settings. | |||
MaxGitDiffLines int | |||
GitFsckArgs []string | |||
GitGcArgs []string | |||
// I18n settings. | |||
Langs, Names []string | |||
@@ -288,6 +290,8 @@ func NewConfigContext() { | |||
DisableGravatar = Cfg.MustBool("picture", "DISABLE_GRAVATAR") | |||
MaxGitDiffLines = Cfg.MustInt("git", "MAX_GITDIFF_LINES", 10000) | |||
GitFsckArgs = Cfg.MustValueArray("git", "FSCK_ARGS", " ") | |||
GitGcArgs = Cfg.MustValueArray("git", "GC_ARGS", " ") | |||
Langs = Cfg.MustValueArray("i18n", "LANGS", ",") | |||
Names = Cfg.MustValueArray("i18n", "NAMES", ",") |
@@ -117,6 +117,7 @@ const ( | |||
CLEAN_UNBIND_OAUTH AdminOperation = iota + 1 | |||
CLEAN_INACTIVATE_USER | |||
CLEAN_REPO_ARCHIVES | |||
GIT_GC_REPOS | |||
) | |||
func Dashboard(ctx *middleware.Context) { | |||
@@ -140,6 +141,9 @@ func Dashboard(ctx *middleware.Context) { | |||
case CLEAN_REPO_ARCHIVES: | |||
success = ctx.Tr("admin.dashboard.delete_repo_archives_success") | |||
err = models.DeleteRepositoryArchives() | |||
case GIT_GC_REPOS: | |||
success = ctx.Tr("admin.dashboard.git_gc_repos_success") | |||
err = models.GitGcRepos() | |||
} | |||
if err != nil { |
@@ -1 +1 @@ | |||
0.5.8.1128 Beta | |||
0.5.8.1130 Beta |
@@ -44,6 +44,10 @@ | |||
<td>{{.i18n.Tr "admin.dashboard.delete_repo_archives"}}</td> | |||
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=3">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> | |||
</tr> | |||
<tr> | |||
<td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td> | |||
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</div> |