#2018 able to sync now for mirrors

- Refactor code to use sync.UniqueQueue
- Closes #3509
This commit is contained in:
Unknwon committed 2016-08-30 16:18:33 -07:00
1 parent c1ecb6c60a
commit 8516dfcb6c
16 files changed
+345 -242

No files matched your search

+5 -1
View File
@@ -8,10 +8,14 @@ end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.{go,tmpl}] [*.go]
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4
[*.tmpl]
indent_style = tab
indent_size = 2
[*.{less,yml}] [*.{less,yml}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
+1 -1
View File
@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
![](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)
##### Current tip version: 0.9.95 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions) ##### Current tip version: 0.9.96 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
| Web | UI | Preview | | Web | UI | Preview |
|:-------------:|:-------:|:-------:| |:-------------:|:-------:|:-------:|
+6 -4
View File
@@ -17,8 +17,10 @@ ANSI_CHARSET =
FORCE_PRIVATE = false FORCE_PRIVATE = false
; Global maximum creation limit of repository per user, -1 means no limit ; Global maximum creation limit of repository per user, -1 means no limit
MAX_CREATION_LIMIT = -1 MAX_CREATION_LIMIT = -1
; Patch test queue length, make it as large as possible ; Mirror sync queue length, increase if mirror syncing starts hanging
PULL_REQUEST_QUEUE_LENGTH = 10000 MIRROR_QUEUE_LENGTH = 1000
; Patch test queue length, increase if pull request patch testing starts hanging
PULL_REQUEST_QUEUE_LENGTH = 1000
; Preferred Licenses to place at the top of the List ; Preferred Licenses to place at the top of the List
; Name must match file name in conf/license or custom/conf/license ; Name must match file name in conf/license or custom/conf/license
PREFERRED_LICENSES = Apache License 2.0,MIT License PREFERRED_LICENSES = Apache License 2.0,MIT License
@@ -184,7 +186,7 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
ENABLE_CAPTCHA = true ENABLE_CAPTCHA = true
[webhook] [webhook]
; Hook task queue length ; Hook task queue length, increase if webhook shooting starts hanging
QUEUE_LENGTH = 1000 QUEUE_LENGTH = 1000
; Deliver timeout in seconds ; Deliver timeout in seconds
DELIVER_TIMEOUT = 5 DELIVER_TIMEOUT = 5
@@ -389,7 +391,7 @@ GC = 60
[mirror] [mirror]
; Default interval in hours between each check ; Default interval in hours between each check
DEFAULT_INTERVAL = 24 DEFAULT_INTERVAL = 8
[api] [api]
; Max number of items will response in a page ; Max number of items will response in a page
+4
View File
@@ -370,6 +370,7 @@ mirror_prune_desc = Remove any remote-tracking references that no longer exist o
mirror_interval = Mirror Interval (hour) mirror_interval = Mirror Interval (hour)
mirror_address = Mirror Address mirror_address = Mirror Address
mirror_address_desc = Please include necessary user credentials in the address. mirror_address_desc = Please include necessary user credentials in the address.
mirror_last_synced = Last Synced
watchers = Watchers watchers = Watchers
stargazers = Stargazers stargazers = Stargazers
forks = Forks forks = Forks
@@ -631,6 +632,9 @@ settings.collaboration.undefined = Undefined
settings.hooks = Webhooks settings.hooks = Webhooks
settings.githooks = Git Hooks settings.githooks = Git Hooks
settings.basic_settings = Basic Settings settings.basic_settings = Basic Settings
settings.mirror_settings = Mirror Settings
settings.sync_mirror = Sync Now
settings.mirror_sync_in_progress = Mirror syncing is in progress, please refresh page in about a minute.
settings.site = Official Site settings.site = Official Site
settings.update_settings = Update Settings settings.update_settings = Update Settings
settings.change_reponame_prompt = This change will affect how links relate to the repository. settings.change_reponame_prompt = This change will affect how links relate to the repository.
+1 -1
View File
@@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.9.95.0830" const APP_VER = "0.9.96.0830"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
+6 -195
View File
@@ -381,7 +381,7 @@ func (repo *Repository) IssueStats(uid int64, filterMode int, isPull bool) (int6
} }
func (repo *Repository) GetMirror() (err error) { func (repo *Repository) GetMirror() (err error) {
repo.Mirror, err = GetMirror(repo.ID) repo.Mirror, err = GetMirrorByRepoID(repo.ID)
return err return err
} }
@@ -574,136 +574,6 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(false) return repo.cloneLink(false)
} }
// Mirror represents a mirror information of repository.
type Mirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
Interval int // Hour.
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64
NextUpdate time.Time `xorm:"-"`
NextUpdateUnix int64
address string `xorm:"-"`
}
func (m *Mirror) BeforeInsert() {
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
case "repo_id":
m.Repo, err = GetRepositoryByID(m.RepoID)
if err != nil {
log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err)
}
case "updated_unix":
m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
case "next_updated_unix":
m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
}
}
func (m *Mirror) readAddress() {
if len(m.address) > 0 {
return
}
cfg, err := ini.Load(m.Repo.GitConfigPath())
if err != nil {
log.Error(4, "Load: %v", err)
return
}
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
}
// HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL
// with placeholder <credentials>.
// It will fail for any other forms of clone addresses.
func HandleCloneUserCredentials(url string, mosaics bool) string {
i := strings.Index(url, "@")
if i == -1 {
return url
}
start := strings.Index(url, "://")
if start == -1 {
return url
}
if mosaics {
return url[:start+3] + "<credentials>" + url[i:]
}
return url[:start+3] + url[i+1:]
}
// Address returns mirror address from Git repository config without credentials.
func (m *Mirror) Address() string {
m.readAddress()
return HandleCloneUserCredentials(m.address, false)
}
// FullAddress returns mirror address from Git repository config.
func (m *Mirror) FullAddress() string {
m.readAddress()
return m.address
}
// SaveAddress writes new address to Git repository config.
func (m *Mirror) SaveAddress(addr string) error {
configPath := m.Repo.GitConfigPath()
cfg, err := ini.Load(configPath)
if err != nil {
return fmt.Errorf("Load: %v", err)
}
cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
return cfg.SaveToIndent(configPath, "\t")
}
func getMirror(e Engine, repoId int64) (*Mirror, error) {
m := &Mirror{RepoID: repoId}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMirrorNotExist
}
return m, nil
}
// GetMirror returns mirror object by given repository ID.
func GetMirror(repoId int64) (*Mirror, error) {
return getMirror(x, repoId)
}
func updateMirror(e Engine, m *Mirror) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
func DeleteMirrorByRepoID(repoID int64) error {
_, err := x.Delete(&Mirror{RepoID: repoID})
return err
}
func createUpdateHook(repoPath string) error {
return git.SetUpdateHook(repoPath,
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
}
type MigrateRepoOptions struct { type MigrateRepoOptions struct {
Name string Name string
Description string Description string
@@ -839,6 +709,11 @@ func cleanUpMigrateGitConfig(configPath string) error {
return nil return nil
} }
func createUpdateHook(repoPath string) error {
return git.SetUpdateHook(repoPath,
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
}
// 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()
@@ -1748,70 +1623,6 @@ const (
_CHECK_REPOs = "check_repos" _CHECK_REPOs = "check_repos"
) )
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if taskStatusTable.IsRunning(_MIRROR_UPDATE) {
return
}
taskStatusTable.Start(_MIRROR_UPDATE)
defer taskStatusTable.Stop(_MIRROR_UPDATE)
log.Trace("Doing: MirrorUpdate")
mirrors := make([]*Mirror, 0, 10)
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.Repo == nil {
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
return nil
}
repoPath := m.Repo.RepoPath()
wikiPath := m.Repo.WikiPath()
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
gitArgs := []string{"remote", "update"}
if m.EnablePrune {
gitArgs = append(gitArgs, "--prune")
}
if _, stderr, err := process.ExecDir(
timeout, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", gitArgs...); err != nil {
desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return nil
}
if m.Repo.HasWiki() {
if _, stderr, err := process.ExecDir(
timeout, wikiPath, fmt.Sprintf("MirrorUpdate: %s", wikiPath),
"git", "remote", "update", "--prune"); err != nil {
desc := fmt.Sprintf("Fail to update mirror wiki repository(%s): %s", wikiPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return nil
}
}
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
mirrors = append(mirrors, m)
return nil
}); err != nil {
log.Error(4, "MirrorUpdate: %v", err)
}
for i := range mirrors {
if err := UpdateMirror(mirrors[i]); err != nil {
log.Error(4, "UpdateMirror[%d]: %v", mirrors[i].ID, err)
}
}
}
// GitFsck calls 'git fsck' to check repository health. // GitFsck calls 'git fsck' to check repository health.
func GitFsck() { func GitFsck() {
if taskStatusTable.IsRunning(_GIT_FSCK) { if taskStatusTable.IsRunning(_GIT_FSCK) {
+243
View File
@@ -0,0 +1,243 @@
// Copyright 2016 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"
"strings"
"time"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"gopkg.in/ini.v1"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/sync"
)
var MirrorQueue = sync.NewUniqueQueue(setting.Repository.MirrorQueueLength)
// Mirror represents mirror information of a repository.
type Mirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
Repo *Repository `xorm:"-"`
Interval int // Hour.
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
Updated time.Time `xorm:"-"`
UpdatedUnix int64
NextUpdate time.Time `xorm:"-"`
NextUpdateUnix int64
address string `xorm:"-"`
}
func (m *Mirror) BeforeInsert() {
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) BeforeUpdate() {
m.UpdatedUnix = time.Now().Unix()
m.NextUpdateUnix = m.NextUpdate.Unix()
}
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
var err error
switch colName {
case "repo_id":
m.Repo, err = GetRepositoryByID(m.RepoID)
if err != nil {
log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err)
}
case "updated_unix":
m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
case "next_updated_unix":
m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
}
}
// ScheduleNextUpdate calculates and sets next update time.
func (m *Mirror) ScheduleNextUpdate() {
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
}
func (m *Mirror) readAddress() {
if len(m.address) > 0 {
return
}
cfg, err := ini.Load(m.Repo.GitConfigPath())
if err != nil {
log.Error(4, "Load: %v", err)
return
}
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
}
// HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL
// with placeholder <credentials>.
// It will fail for any other forms of clone addresses.
func HandleCloneUserCredentials(url string, mosaics bool) string {
i := strings.Index(url, "@")
if i == -1 {
return url
}
start := strings.Index(url, "://")
if start == -1 {
return url
}
if mosaics {
return url[:start+3] + "<credentials>" + url[i:]
}
return url[:start+3] + url[i+1:]
}
// Address returns mirror address from Git repository config without credentials.
func (m *Mirror) Address() string {
m.readAddress()
return HandleCloneUserCredentials(m.address, false)
}
// FullAddress returns mirror address from Git repository config.
func (m *Mirror) FullAddress() string {
m.readAddress()
return m.address
}
// SaveAddress writes new address to Git repository config.
func (m *Mirror) SaveAddress(addr string) error {
configPath := m.Repo.GitConfigPath()
cfg, err := ini.Load(configPath)
if err != nil {
return fmt.Errorf("Load: %v", err)
}
cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
return cfg.SaveToIndent(configPath, "\t")
}
// runSync returns true if sync finished without error.
func (m *Mirror) runSync() bool {
repoPath := m.Repo.RepoPath()
wikiPath := m.Repo.WikiPath()
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
gitArgs := []string{"remote", "update"}
if m.EnablePrune {
gitArgs = append(gitArgs, "--prune")
}
if _, stderr, err := process.ExecDir(
timeout, repoPath, fmt.Sprintf("runSync: %s", repoPath),
"git", gitArgs...); err != nil {
desc := fmt.Sprintf("Fail to update mirror repository '%s': %s", repoPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return false
}
if m.Repo.HasWiki() {
if _, stderr, err := process.ExecDir(
timeout, wikiPath, fmt.Sprintf("runSync: %s", wikiPath),
"git", "remote", "update", "--prune"); err != nil {
desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr)
log.Error(4, desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "CreateRepositoryNotice: %v", err)
}
return false
}
}
return true
}
func getMirrorByRepoID(e Engine, repoID int64) (*Mirror, error) {
m := &Mirror{RepoID: repoID}
has, err := e.Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMirrorNotExist
}
return m, nil
}
// GetMirrorByRepoID returns mirror information of a repository.
func GetMirrorByRepoID(repoID int64) (*Mirror, error) {
return getMirrorByRepoID(x, repoID)
}
func updateMirror(e Engine, m *Mirror) error {
_, err := e.Id(m.ID).AllCols().Update(m)
return err
}
func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
func DeleteMirrorByRepoID(repoID int64) error {
_, err := x.Delete(&Mirror{RepoID: repoID})
return err
}
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if taskStatusTable.IsRunning(_MIRROR_UPDATE) {
return
}
taskStatusTable.Start(_MIRROR_UPDATE)
defer taskStatusTable.Stop(_MIRROR_UPDATE)
log.Trace("Doing: MirrorUpdate")
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.Repo == nil {
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
return nil
}
MirrorQueue.Add(m.RepoID)
return nil
}); err != nil {
log.Error(4, "MirrorUpdate: %v", err)
}
}
// SyncMirrors checks and syncs mirrors.
// TODO: sync more mirrors at same time.
func SyncMirrors() {
// Start listening on new sync requests.
for repoID := range MirrorQueue.Queue() {
log.Trace("SyncMirrors [repo_id: %v]", repoID)
MirrorQueue.Remove(repoID)
m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
if err != nil {
log.Error(4, "GetMirrorByRepoID [%d]: %v", repoID, err)
continue
}
if !m.runSync() {
continue
}
m.ScheduleNextUpdate()
if err = UpdateMirror(m); err != nil {
log.Error(4, "UpdateMirror [%d]: %v", repoID, err)
continue
}
}
}
func InitSyncMirrors() {
go SyncMirrors()
}
+1 -1
View File
@@ -597,7 +597,7 @@ func DeliverHooks() {
// Start listening on new hook requests. // Start listening on new hook requests.
for repoID := range HookQueue.Queue() { for repoID := range HookQueue.Queue() {
log.Trace("DeliverHooks [%v]: processing delivery hooks", repoID) log.Trace("DeliverHooks [repo_id: %v]", repoID)
HookQueue.Remove(repoID) HookQueue.Remove(repoID)
tasks = make([]*HookTask, 0, 5) tasks = make([]*HookTask, 0, 5)
+4 -4
View File
@@ -287,7 +287,7 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil return nil
} }
var _confAppIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x7b\x5b\x6f\x23\xc9\x75\xff\x7b\x7f\x8a\x5a\xed\x7f\xff\xa3\x09\x9a\xa4\x2e\x23\x8d\x56\xb6\x9c\xa5\xc8\xa6\x44\x0f\x6f\xee\xa6\x66\x76\x76\x20\xb4\x5a\xec\x22\xd9\xab\x66\x37\xb7\xab\x29\x8d\x16\x41\x60\x23\x0f\xb9\x00\x41\x1e\x12\x24\x08\x10\x04\xc9\x43\x62\xc0\xb9\xd9\xc8\x8b\x9d\x6c\xf2\xb2\xc9\xfb\xec\x77\x70\xd6\xf1\x93\xbf\x42\x7e\xe7\x54\x35\xd9\xd4\x68\x95\xdd\x20\x17\xaf\xd8\x97\xaa\x53\x75\xee\xbf\x73\xaa\xe7\x5d\xd1\x73\x9e\x3b\xae\xe0\x3f\xdd\x7e\xb3\xdd\x7a\x29\x86\xa7\x6d\x4f\xb4\xda\x1d\xc7\x7a\x57\x0c\x3a\x4e\xdd\x73\x44\xb7\xfe\xcc\x11\x8d\xd3\x7a\xef\xc4\xf1\x44\xbf\x27\x1a\x7d\xd7\x75\xbc\x41\xbf\xd7\x6c\xf7\x4e\x44\xe3\xcc\x1b\xf6\xbb\x78\xd8\x6b\xb5\x4f\xf4\x4c\xeb\x5b\xa2\x3e\x9f\x8b\x24\x98\x49\x91\x4f\x83\x5c\xa8\x69\x7a\xa3\x44\x9a\x08\x79\x2d\xb3\x5b\x31\x0f\x26\x78\x11\xe5\xb1\xb4\xea\x83\x81\xdf\xab\x77\x1d\x71\x24\x4e\xd2\x89\x3a\xc4\x5f\x71\x12\xe5\xc2\x93\xd9\x75\x34\x92\xa0\xd4\x98\x06\x09\x86\xe3\x59\x34\x16\xb7\xe9\x42\x64\x8b\x44\xc4\xe9\x28\x88\xe3\x5b\xcb\x3d\xeb\xf9\x67\x1e\x76\x7f\x24\x26\x51\x8e\xd1\x4e\x94\x4f\x65\x26\x36\x42\x79\xbd\x61\x8b\x8d\x79\x96\x86\x1b\x22\xc5\x83\x5c\xaa\x1c\x4f\x42\x39\x0e\x16\x31\x68\x29\x3d\x86\x29\x80\x75\xda\x00\xee\x2d\xeb\x55\x26\xe7\xa9\x8a\xf2\x34\xbb\x3d\xb7\xdc\x7e\x7f\x28\x8e\x2c\xaf\xe1\xb6\x07\x43\x7f\xf8\x72\x40\xc3\x2e\x03\x35\xc5\x4a\x4d\x43\xa9\xde\xf3\xda\x62\x34\x0d\x32\x25\x73\x8b\x6e\x7c\x88\xca\xf5\x1c\x9a\xf8\x2d\xd1\x4a\xb3\x91\x34\x6c\x27\xf2\x46\xac\xa8\x8b\x3c\x15\x97\x52\xcc\xb3\xe8\x3a\xc8\xa5\xd5\xea\xbb\x0d\xc7\x1f\xb8\xed\xe7\xf5\x21\xad\x32\x0e\x62\x45\xec\x9f\xc4\xe9\x65\x10\x8b\x59\xf0\x3a\x9a\x2d\x66\x62\x94\xc9\x20\x8f\x20\xc9\x38\x9a\x41\x24\xe9\xb8\x4c\x71\x0e\xce\x17\x4a\x66\xb6\xa8\x6c\x8b\x99\x0c\x12\x25\x92\x54\x8f\xb4\xba\xf5\x0f\xfd\x86\xeb\xd4\x87\xed\x7e\xcf\xef\xb4\xbb\x6d\xec\x0f\xc3\xb0\xc2\x20\xc8\x47\x53\x41\xf2\x11\x9f\x2c\xe4\x42\x8a\x58\x26\x93\x7c\x6a\x63\xcd\x2b\x96\x7b\xa0\x44\x1c\x64\xd0\x01\x2e\xb0\x96\x8a\x2e\xa1\xb8\xc1\x59\xa7\xe3\xbb\xce\xf7\xce\x1c\x6f\xe8\xe3\xef\x99\xe3\x77\x9c\xde\xc9\xf0\x14\x64\xb7\xb7\xf0\x7f\x44\x39\x93\x63\x99\x65\x32\x14\x1d\xe8\x32\x51\x52\x11\xd3\xf3\x38\x80\x48\x60\x15\xd0\x14\xee\xe7\xc4\x04\x5d\x76\x22\x45\x1a\xec\x91\xd5\xcc\x16\xd8\xcd\x8c\x37\x36\x8e\x62\xa9\x4d\x29\x4a\xc4\x28\x4d\xc6\xb5\x58\x13\x23\xb5\x8e\x30\x2e\x9d\xd5\xca\x8f\xad\x81\xeb\xb4\x1c\x58\x68\x13\x6c\x36\x9c\x9e\x07\xa3\x3d\x82\x3d\x06\x23\x5e\x43\x4f\xdd\xa9\x6e\xd9\x24\x02\x73\xbf\xa6\xf6\xaa\x0c\xe9\xf7\x1c\x7b\xa1\x2d\xd1\xf6\x78\x0f\xf2\x75\x8e\xb1\x90\xbd\x5a\x1a\xf5\x22\x0e\xc5\x34\xb8\x86\xc8\xa2\x44\x8a\x9b\x2c\x98\x2b\xda\x25\x71\xd3\x48\x43\xd9\x8d\xb2\x0c\x9b\xd4\xf4\x40\xce\x93\xf3\x20\x83\xb2\xcb\xa4\x6e\x60\xb0\x22\x00\x63\xb3\x59\x50\x15\xc3\x74\x45\x8a\x57\xc5\x80\x5a\xba\x1a\x6f\x8b\x8f\x49\x32\xf3\x45\x5e\xcc\xb1\x3a\xed\x9e\xe3\xbf\x70\xeb\x03\xdf\xf9\x70\x08\x76\xa1\x5f\x62\xb8\x9a\xbf\xce\xed\xea\x2c\xc4\x7f\x41\x76\x15\xa6\x37\x09\xdd\xe9\x9f\xab\xd0\xc6\x6e\x9e\x07\x71\x14\x6a\xd6\x66\xd8\xac\xe1\x8a\xd9\x09\x60\x96\xf2\x3a\x82\xbd\xd6\x07\x6d\xa8\x5d\xa5\xa3\x08\xfb\x0e\xf5\x6e\xc1\xde\xcc\x16\x6a\x01\xe5\xc0\x22\x82\x79\x54\xbb\xde\xae\x15\xab\x94\xd9\xbc\x0e\xe2\x05\xe8\x5e\xde\xea\xad\xaa\x2a\x59\x04\x93\xcd\x83\x4b\x12\x14\x49\x86\x17\x17\x37\x69\xf2\x48\xc7\x09\x72\x73\x12\xe0\xba\xcc\x45\x98\x4a\x45\x43\xd8\x28\x48\xc7\xcf\xdb\xce\x8b\xfa\x71\xc7\xf1\x29\xe4\xb0\x0b\x13\xdb\xcb\x6d\xac\x69\x74\x31\x8f\xd3\x20\x24\x8d\xbe\x98\x4a\x0e\x10\x25\xaf\xe1\x85\xf4\x08\x70\x93\x61\xd1\x24\x80\x85\x87\xd5\xc2\xc5\xd9\x6a\x2f\xf2\x6c\x21\x2f\x2c\xa7\x47\x6b\x36\xb1\x12\xdd\x6b\xef\x81\x8d\x42\xcb\x86\xc2\x9d\x59\x61\x90\x07\xb5\x7c\x36\xaf\x99\xd7\x17\x62\x13\x77\x62\x22\xf1\x3e\x94\xb1\x24\xa1\x82\xbb\x09\x62\x1f\xf6\xa4\xf2\x20\xcb\x1f\x5b\x43\xa7\x3b\xf0\x07\x75\xf6\xa5\xbb\x04\xb0\x64\x3f\x61\xdb\x9f\xa5\xd8\x2b\xa2\x60\x7a\x03\x1a\xf9\xed\x5c\x2a\x5b\xc8\xea\xa4\x2a\xa2\x19\xe2\x6b\xed\xe3\xb9\x9c\xfc\x86\xbe\x9c\x27\x78\xda\x4b\xf3\x69\x94\x4c\x4c\x5c\x08\x12\xc3\x38\x4d\xb4\xea\x9d\x4e\xff\x05\x1c\x86\x22\x9c\xc7\x71\xab\x1b\xbc\x16\x2a\xfa\x54\x92\xf5\xcb\xa0\x70\x43\xa8\xac\x7b\xbc\xce\xe1\x6e\xf7\xd8\xd2\x1a\x40\x80\xf1\xda\x1f\x51\xec\xda\x35\x04\x92\xc5\xec\x12\xb2\x36\x0e\xa4\x74\x7c\x62\x36\xd6\x69\xec\x71\x74\x22\x2a\xa4\xc2\x3d\xe8\x6e\x11\x91\xb2\x7a\xcb\xf9\x4b\x75\x45\x85\x9d\x92\xa2\xc8\x5c\xc0\x3b\x76\x95\x26\x64\x2b\x20\x8d\xa7\x94\x5d\x2c\xe7\xc3\x41\xa7\xef\x22\xa0\xd6\x4f\x90\xa4\xfc\xde\x59\x17\x94\x77\xb6\xd6\x88\x46\x4a\x2d\xbe\x9a\x1c\x93\x69\x7b\xde\xd9\x1d\x22\xdb\xeb\x44\x96\x81\x19\x16\x1e\x81\x9d\x75\x22\xc1\x28\x8f\xae\xa3\x1c\xb2\x96\x32\xb4\x5a\x0e\x64\xcc\x81\xb8\xdf\x45\xf4\x31\x04\xf7\xb4\x2f\x2e\x58\xd6\x17\xe4\x5c\xb2\x32\x4a\xc1\xca\x05\x74\x95\x07\xf0\x95\x89\x4d\x61\x3d\x24\x47\xaa\x27\x61\x96\xc2\x6d\xbf\x83\x79\x55\xda\x49\x3d\xc1\x5a\xd7\xec\xca\x3c\x09\xf1\x03\x51\x7b\x23\xc1\xea\x3a\xf1\x85\x91\x22\x73\xde\x80\xef\xc6\xb1\x76\x6f\x72\Line truncated var _confAppIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x7b\x5b\x6f\x23\xd9\x75\xee\x7b\xfd\x8a\x3d\x9a\x33\xa7\xd5\x07\x45\x52\x97\x96\x5a\x23\x5b\x3e\x43\x91\x45\x89\x6e\xde\x5c\x45\x75\x4f\x4f\x43\x28\x95\x58\x9b\x64\x8d\x8a\x55\x9c\xda\x45\xa9\x35\x38\x38\xb0\x91\x87\x5c\x80\x20\x0f\x09\x12\x04\x08\x82\xe4\x21\x31\xe0\xdc\x6c\xe4\xc5\x4e\x9c\xbc\x4c\xf2\xde\xf3\x1f\x9c\x71\xfc\xe4\xbf\x90\x6f\xad\xbd\x8b\x2c\xaa\xd5\xca\x4c\x90\xc0\x1e\xb1\x2e\x7b\xaf\xbd\xd7\xfd\x5b\x6b\x57\xbf\x2f\x7a\xce\x73\xc7\x15\xfc\xa7\xdb\x6f\xb6\x5b\x2f\xc5\xf0\xb4\xed\x89\x56\xbb\xe3\x58\xef\x8b\x41\xc7\xa9\x7b\x8e\xe8\xd6\x9f\x39\xa2\x71\x5a\xef\x9d\x38\x9e\xe8\xf7\x44\xa3\xef\xba\x8e\x37\xe8\xf7\x9a\xed\xde\x89\x68\x9c\x79\xc3\x7e\x17\x0f\x7b\xad\xf6\x89\x9e\x69\x7d\x4b\xd4\xe7\x73\x91\x04\x33\x29\xf2\x69\x90\x0b\x35\x4d\x6f\x94\x48\x13\x21\xaf\x65\x76\x2b\xe6\xc1\x04\x2f\xa2\x3c\x96\x56\x7d\x30\xf0\x7b\xf5\xae\x23\x8e\xc4\x49\x3a\x51\x87\xf8\x2b\x4e\xa2\x5c\x78\x32\xbb\x8e\x46\x12\x94\x1a\xd3\x20\xc1\x70\x3c\x8b\xc6\xe2\x36\x5d\x88\x6c\x91\x88\x38\x1d\x05\x71\x7c\x6b\xb9\x67\x3d\xff\xcc\xc3\xee\x8f\xc4\x24\xca\x31\xda\x89\xf2\xa9\xcc\xc4\x46\x28\xaf\x37\x6c\xb1\x31\xcf\xd2\x70\x43\xa4\x78\x90\x4b\x95\xe3\x49\x28\xc7\xc1\x22\x06\x2d\xa5\xc7\x30\x05\xb0\x4e\x1b\xc0\xbd\x65\xbd\xca\xe4\x3c\x55\x51\x9e\x66\xb7\xe7\x96\xdb\xef\x0f\xc5\x91\xe5\x35\xdc\xf6\x60\xe8\x0f\x5f\x0e\x68\xd8\x65\xa0\xa6\x58\xa9\x69\x28\xd5\x7b\x5e\x5b\x8c\xa6\x41\xa6\x64\x6e\xd1\x8d\x0f\x51\xb9\x9e\x43\x13\xbf\x25\x5a\x69\x36\x92\x86\xed\x44\xde\x88\x15\x75\x91\xa7\xe2\x52\x8a\x79\x16\x5d\x07\xb9\xb4\x5a\x7d\xb7\xe1\xf8\x03\xb7\xfd\xbc\x3e\xa4\x55\xc6\x41\xac\x88\xfd\x93\x38\xbd\x0c\x62\x31\x0b\x5e\x47\xb3\xc5\x4c\x8c\x32\x19\xe4\x11\x24\x19\x47\x33\x88\x24\x1d\x97\x29\xce\xc1\xf9\x42\xc9\xcc\x16\x95\x6d\x31\x93\x41\xa2\x44\x92\xea\x91\x56\xb7\xfe\xb1\xdf\x70\x9d\xfa\xb0\xdd\xef\xf9\x9d\x76\xb7\x8d\xfd\x61\x18\x56\xe8\x46\x59\x06\x09\xa9\xdb\x64\x24\x3e\x5b\xc8\x85\x14\xb1\x4c\x26\xf9\xd4\x16\x51\x42\xcb\x29\x49\x92\x9f\xad\x46\x45\xc9\x44\xa8\x3c\xc8\x72\x25\x48\x37\xb8\xb5\xba\x6d\xd7\xed\xbb\xfe\xf7\xce\x9c\x33\xc7\xef\x38\xbd\x93\xe1\x29\xc8\x6f\x6f\x6d\x6d\x61\x81\x41\x90\x8f\xa6\x82\x14\xf0\x00\xfd\xf9\x22\x8e\xc1\x0b\x06\x60\xd8\x7c\x39\xe3\x9e\xb5\x06\x67\x9d\x8e\xef\x3a\x58\xcb\x1b\xbe\x6b\xc5\x4c\x8e\x65\x96\xc9\x50\x74\x60\x44\x89\x92\x8a\xa4\x3d\x8f\x03\xe8\x02\xe6\x08\x13\xc1\xfd\x9c\xa4\x47\x97\x9d\x48\x91\xe9\xf4\xc8\x5c\x67\x0b\x2c\x3f\xe3\xe5\xc7\x51\x2c\xb5\x0d\x47\x89\x18\xa5\xc9\xb8\x16\x6b\x62\x64\x4f\x23\x8c\x4b\x67\xb5\xf2\x63\x6b\xe0\x3a\x2d\x07\xae\xd1\x84\x7c\x1b\x4e\xcf\x83\xb7\x1c\xc1\x11\x82\x11\xaf\xa1\xa7\xee\x54\xb7\x6c\x92\xbd\xb9\x5f\xb3\xb7\xaa\x0c\xe9\xf7\x1c\x7b\xa1\x2d\xd1\xf6\x78\x0f\xf2\x75\x8e\xb1\x50\xba\x5a\x7a\xd3\x22\x0e\x21\x8f\x6b\x88\x32\x4a\xa4\xb8\xc9\x82\xb9\xa2\x5d\x12\x37\x8d\x34\x94\x46\xa5\x9a\x1e\xc8\x79\x72\x1e\x64\xb0\xb2\x32\xa9\x1b\x78\x8a\x08\xc0\xd8\x6c\x16\x54\xc5\x30\x5d\x91\xe2\x55\x31\xa0\x96\xae\xc6\xdb\xe2\x53\x92\xcc\x7c\x91\x17\x73\xac\x4e\xbb\xe7\xf8\x2f\xdc\xfa\xc0\x77\x3e\x1e\x82\x5d\x18\x16\x31\x5c\xcd\x5f\xe7\x76\x75\x16\xe2\xbf\x20\xbb\x0a\xd3\x9b\x84\xee\xf4\xcf\x55\x68\x63\x37\xcf\x83\x38\x0a\x35\x6b\x33\x6c\xd6\x70\xc5\xec\x04\xf0\x07\x79\x1d\xc1\x51\xea\x83\xb6\x08\x94\x4a\x47\x11\xf6\x1d\xea\xdd\x82\xbd\x99\x2d\xd4\x02\xca\x09\x94\x08\xe6\x51\xed\x7a\xbb\x56\xac\x52\x66\xf3\x3a\x88\x61\x47\xe2\xf2\x56\x6f\x55\x55\xc9\x22\x98\x6c\x1e\x5c\x92\xa0\x48\x32\xbc\xb8\xb8\x49\x93\x47\x3a\x40\x91\x15\x92\x00\xd7\x65\x2e\xc2\x54\x2a\x1a\xc2\x46\x41\x3a\x7e\xde\x76\x5e\xd4\x8f\x3b\x8e\x4f\xb1\x8e\x63\x07\xb1\xbd\xdc\xc6\x9a\x46\x17\xf3\x38\x0d\x42\xd2\xe8\x8b\xa9\xe4\xc8\x54\x72\x57\x5e\x48\x8f\x00\x37\x19\x16\x4d\x82\xcb\x58\x86\xd5\x22\xb6\xb0\xd5\x5e\xe4\xd9\x42\x5e\x58\x4e\x8f\xd6\x6c\x62\x25\xba\xd7\x5e\x05\x1b\x85\x96\x0d\x85\x3b\xb3\xc2\x20\x0f\x6a\xf9\x6c\x5e\x33\xaf\x2f\xc4\x26\xee\xc4\x44\xe2\x7d\x28\x63\x49\x42\x05\x77\x13\x04\x5d\xec\x89\x5d\xec\xb1\x35\x74\xba\x03\x7f\x50\x67\x57\xba\x4b\x00\x4b\xf6\x13\xb6\xfd\x59\x8a\xbd\x22\xfc\xa6\x37\xa0\x91\xdf\xce\xa5\xb2\x85\xac\x4e\xaa\x22\x9a\x21\xb0\xd7\x3e\x9d\xcb\xc9\xff\xd3\x97\xf3\x04\x4f\x7b\x69\x3e\x25\x37\xd6\x01\x29\x48\x0c\xe3\x34\xd1\xaa\x77\x3a\xfd\x17\x70\x18\x0a\xad\x1e\x07\xcc\x6e\xf0\x5a\xa8\xe8\x73\x49\xd6\x2f\x83\xc2\x0d\xa1\xb2\xee\xf1\x3a\x87\xbb\xdd\x63\x4b\x6b\x00\x91\xcd\x6b\x7f\x42\x41\x73\xd7\x10\x48\x16\xb3\x4b\xc8\xda\x38\x90\xd2\x81\x91\xd9\x58\xa7\xb1\xc7\x61\x91\xa8\x90\x0a\xf7\xa0\xbb\x45\x44\xca\xea\x2d\xe7\x2f\xd5\x15\x15\x76\x4a\x8a\x22\x73\x01\xef\xd8\x55\x9a\x90\xad\x80\x34\x9e\x52\x5a\xb3\x9c\x8f\x07\x9d\xbe\x8b\x48\x5e\x3f\x41\x76\xf4\x7b\x67\x5d\x50\xde\xd9\x5a\x23\x1a\x29\xb5\x78\x37\x39\x26\xd3\xf6\xbc\xb3\x3b\x44\xb6\xd7\x89\x2c\x33\x02\x2c\x3c\x02\x3b\xeb\x44\x82\x51\x1e\x5d\x47\x39\x64\x2d\x65\x68\xb5\x1c\xc8\x98\x33\x40\xbf\x8b\xe8\x63\x08\xee\x69\x5f\x5c\xb0\xac\x2f\xc8\xb9\x64\x65\x94\x82\x95\x0b\xe8\x2a\x0f\xe0\x2b\x13\x9b\xf2\x49\x48\x8e\x54\x4f\xc2\x2c\x85\xdb\x7e\Line truncated
func confAppIniBytes() ([]byte, error) { func confAppIniBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@@ -302,7 +302,7 @@ func confAppIni() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "conf/app.ini", size: 13629, mode: os.FileMode(420), modTime: time.Unix(1472559839, 0)} info := bindataFileInfo{name: "conf/app.ini", size: 13794, mode: os.FileMode(420), modTime: time.Unix(1472597235, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@@ -4367,7 +4367,7 @@ func confLocaleLocale_deDeIni() (*asset, error) {
return a, nil return a, nil
} }
var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xac\xbd\xe9\x92\xdb\x48\x92\x27\xfe\x1d\x4f\x81\x52\x9b\x4c\x92\x59\x8a\xb2\xea\x9e\xff\x61\x65\x75\x6c\x56\xaa\x74\xcc\xe8\xc8\x51\xa6\xba\xb7\xb7\x4c\xc6\x02\x49\x24\x89\x11\x09\xb0\x01\x50\xa9\xec\xb6\x36\xdb\x07\xd8\x07\xd8\x7d\xbd\x79\x92\x75\xff\xb9\x7b\x84\x07\x00\x66\x4a\xdd\xa3\x0f\x4a\x30\xc2\xe3\xf6\xf0\xf0\x2b\x3c\x8a\xfd\x7e\xbe\x2a\xbb\x65\xfe\x43\x7e\x9a\xef\x8b\xaa\xde\x96\x5d\x97\x77\xe5\xf6\xea\xf1\xa6\xe9\xfa\x72\x95\x3f\xaf\x7a\xfa\xdd\x7e\xaa\x96\x65\x96\x6d\x9a\x5d\x49\xa0\x2f\xe8\x4f\xb6\x2a\xba\xcd\xa2\x29\xda\x15\x25\x3c\xb5\xef\xac\xfc\xbc\xdf\x36\x2d\x03\xfd\x22\x5f\xd9\xa6\xdc\xee\xb9\x0c\xfd\xc9\xba\x6a\x5d\xcf\xab\x9a\x7e\x5e\xd0\x57\xfe\xb2\x96\x94\xe6\xd0\x5b\xd2\xdb\x43\x2f\x69\x87\xbd\x25\xbd\xdf\x67\x6d\xb9\xae\xa8\x37\x2d\x25\xbd\xd3\xcf\xec\xba\x5c\x74\x55\xcf\x2d\xfd\x49\xbe\xb2\x4f\x65\xdb\x55\x0d\xd7\xfe\x47\xf9\xca\xf6\xc5\x9a\x01\xce\xe9\x4f\xd6\x97\xbb\xfd\xb6\x40\x81\x4b\xfd\xcc\xb6\x45\xbd\x3e\x08\xcc\x2b\xfd\xcc\x96\x6d\x49\x59\xf3\xba\xbc\xa6\xd4\x33\xfc\x98\xcd\x66\xd9\x81\x26\x61\xbe\x6f\x9b\xab\x6a\x5b\xce\x8b\x7a\x35\xdf\xc9\x30\xdf\x53\x7a\xae\xe9\x39\xa5\xe7\x9c\x8e\x21\x94\x2b\x1a\xea\xbc\xe8\x74\x1c\x34\x97\x34\xf2\xa2\xcb\x50\x55\x5d\xec\xac\x34\x7f\x66\xe5\xae\xa8\xb6\x3c\x6b\xfc\x97\xfa\xdd\x75\xd7\x0d\xa6\xf6\x5c\x3f\x69\x0e\xe6\xfd\xcd\xbe\xc4\x14\x3c\xbe\xa4\xaf\x6c\x59\xec\xfb\xe5\xa6\xe0\x6e\xca\x57\x46\x40\xfb\x86\xe6\xa2\x69\x6f\x00\x67\x3f\xb2\xa6\x5d\x17\x75\xf5\xd7\xa2\x97\xf9\x79\xeb\x7e\x66\xbb\xaa\x6d\x1b\x9e\xda\xd7\xf8\xc8\x68\xe4\x73\xae\x87\x52\xde\xd0\x24\xb8\x5a\x38\x67\x57\xad\x5b\x99\x45\xce\x7c\x8d\x5f\x5c\x8b\xe4\x69\x4d\x92\x15\x6a\xbb\x6a\xda\x8f\x9a\xfa\x8c\x3f\x07\x55\x52\xe7\x34\x37\xed\x57\x51\xd3\x7a\x68\xee\x6b\xfc\x48\x00\xba\xac\x58\xed\x68\x86\xf7\x45\x5d\xf2\xd4\x9d\xf2\x2f\x9a\x2f\xfa\x95\x15\xcb\x65\x73\xa8\xfb\x79\x57\xf6\x7d\x55\xaf\x79\x0d\x4e\x25\x29\xbf\xd0\xa4\xcc\xe5\x85\xb4\x9b\xe6\x10\x56\x99\xd2\xff\x4c\x3f\xf3\x73\xf9\x29\x79\xae\x10\x32\x43\x49\x6a\xb2\xaf\x3e\x55\x7d\x55\x4a\x63\xf6\x23\xdb\x1f\xb6\x5b\x9a\xcf\xbf\x1c\xca\xae\xe7\xac\x73\xfa\x4d\x33\x20\xbf\xb3\xaa\xeb\x0e\x28\xf1\x12\x1f\x19\x2d\x6a\xbd\xc4\x70\xce\xf0\x91\x65\xbf\x56\x75\xd7\x17\xdb\xed\x87\x4c\x3f\x18\x58\xbe\x64\x9e\xfa\xaa\x47\x67\x35\x31\xbf\xe8\xcb\x7d\xc7\x13\x9d\x3f\xab\xda\xae\x7f\xdc\x57\x84\x6a\xef\x0e\x75\xb6\x6a\x96\x1f\x09\x89\x79\x43\x62\x2b\xbd\xbc\xca\x69\x4c\x0f\x08\x8d\xdb\x43\x5d\xd3\x28\xf2\xe7\x0d\x8d\x8c\x9a\xa9\x56\x65\xfe\x14\xd0\x27\xf9\x7e\x5b\x16\x1d\x81\x94\xc5\x2a\xff\xbe\xc8\xfb\xa2\x5d\x97\xfd\x0f\xf7\xe6\x0b\xda\x3c\x1f\xef\xe5\x9b\xb6\xbc\xfa\xe1\xde\xfd\xee\xde\x8f\xcf\x0f\x54\x6c\x5b\xd5\x65\xf7\xfd\x93\xe2\xc7\x7c\x59\x50\x0e\x8d\xf5\x26\x5f\x94\x57\xbc\x57\xa8\xad\x9c\x90\xb4\x5e\xf3\x3e\xb9\xe9\x37\xdc\x20\x2d\x18\x7d\x74\x39\x6f\xd4\x6f\x32\x9e\x25\xda\xc8\xf3\xd5\xc2\x88\x12\x3a\x84\xe4\x96\x66\xe9\xf5\xcd\xc5\xbf\xbf\x3a\xc9\xcf\x89\x32\xad\xdb\x12\xdf\xf4\x1f\x95\xf8\x43\x4e\xa3\xbd\xac\x9e\xfe\x3c\xcb\xa8\xac\x4d\xc8\xd3\xa2\x2f\x16\xdc\xf7\xb0\x48\x9c\x29\x7b\x28\xe4\x61\x27\x31\xad\x03\x5d\xeb\x7a\xec\x4e\xdd\x99\x93\xfb\x90\xea\xd0\xcd\x1b\xea\x78\xc3\x3b\x98\xd2\xc3\xcc\x9e\xcb\x9c\x51\x55\xf9\xcb\x37\x6f\xde\x3e\xfd\x39\x2f\xeb\x35\xcd\x4c\x7e\x5d\xf5\x9b\xfc\xd0\x5f\xfd\xff\xf3\x75\x59\x97\x6d\xb1\x9d\x2f\x2b\x9e\x94\x96\xf0\x2a\xa7\x59\x92\x21\xce\xb2\xae\xdb\x12\x81\x59\x71\x2b\x17\x17\xaf\xf2\xd7\xf4\x49\x9d\xa1\xb2\xdc\x91\x7e\x93\x75\x7f\xd9\xf2\x44\x85\x06\x2f\x37\x65\x0e\x9c\x05\x50\x73\x35\x9c\x97\x7c\xa5\x7d\x9d\xe5\xdf\x2f\xda\x1f\x5d\xff\x8a\x45\xd7\x6c\x0f\xbd\x96\xbc\xde\x94\x35\x16\x8a\x50\xa9\xed\x89\x5a\x19\xed\x9f\x65\x65\xdb\xce\x89\x6e\xf6\x37\xbc\x3c\xda\x97\x63\xad\x48\x65\x84\xca\x75\xd3\xd3\xf2\xe7\x28\x27\x55\x54\xf5\xa7\x62\x5b\xad\x68\x91\xe2\x44\xa6\x65\x91\xb8\x6a\x68\xbd\xb9\x34\x61\x74\x73\x8d\x29\xa2\x0d\x46\x64\x3d\xbf\x37\xbb\x07\x3a\x7b\xef\xf1\xbd\x59\x56\x37\x73\x21\x02\x4c\x91\x57\x55\x57\x2c\x88\x3a\xcb\x69\xd1\x1a\xb1\xfb\x33\xe3\x9d\x74\x45\x21\xf2\x04\x82\xd7\x84\x4f\x20\x10\x7e\x46\xca\x82\xc8\x34\x68\x89\x52\x11\x3f\x76\x23\x39\x01\x2f\x84\xea\x84\x84\xd1\x98\x33\x5b\x68\xc3\xca\xd3\xfd\x7e\x5b\x2d\xa5\xe9\xe7\x92\x17\x11\x94\xcf\x63\x9d\x14\x0f\x07\x04\xb3\x3c\x87\x66\xd4\x6b\xa6\x4a\x79\x42\xde\x51\x7e\x53\xd2\x8e\xdb\x1c\xd6\x72\x26\x6d\x9b\xc3\xea\x1b\x1c\x0e\xb6\x72\x91\x04\xe7\xef\x1a\xea\x30\xb0\x2a\x00\xc4\x26\x4e\x89\xa0\x30\x0b\xd0\x96\xbb\xa6\xe7\x89\xd3\x62\x4c\xe6\xae\x2b\xca\xa4\x91\x76\xc5\x27\x3a\xdc\xfa\x46\xb6\xf2\x8a\xb6\xea\x92\x2b\x9e\x65\x44\x56\xe6\xba\x9d\x88\xfe\xc8\x96\xb2\xb4\x14\x77\x01\xb5\x3b\xd0\x2e\xdc\x50\x65\x3c\xf1\xcc\x87\x50\x95\x53\xfd\xc4\x90\xa8\x1e\x50\x07\xda\xf1\x0d\x9d\x99\xbc\xd0\x4f\xf1\xa1\xbf\x7d\xfd\xd4\xab\xe2\xea\x8a\x7a\xd5\xd1\x6e\x7a\x91\x2f\xb7\x0d\x6d\xc5\xf7\xef\x5e\x75\xbc\xd1\x36\xf3\x7d\xd3\x82\xff\xa0\xac\x73\xfa\x0c\x69\x6e\xa2\x19\xa2\x3e\xec\x16\xf4\xeb\x7a\x53\x2d\x37\x32\xed\x5c\x82\xf7\x07\xa5\x5Line truncated var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xac\xbd\xeb\x72\xdb\x48\xb2\x27\xfe\x1d\x4f\x81\xf6\x84\xc3\x76\x84\x4c\x47\xcf\x9c\xff\x25\x3a\xfa\xb2\x6a\xb9\xdd\xf6\x39\x96\xad\x63\xa9\x67\x76\xb6\xc3\xc1\x06\x49\x88\xc4\x31\x09\x70\x00\xd0\xb2\x66\x62\x22\xf6\x01\xf6\x01\x76\x5f\xef\x3c\xc9\x66\xfe\x32\xb3\x2a\x0b\x00\x25\x7b\xe6\xf8\x83\x45\x54\x65\xdd\xb3\xb2\xf2\x56\x59\xc5\x7e\x3f\x5f\x95\xdd\x32\xff\x2e\x3f\xcd\xf7\x45\x55\x6f\xcb\xae\xcb\xbb\x72\x7b\xfd\x74\xd3\x74\x7d\xb9\xca\x7f\xae\x7a\xfa\x6e\x3f\x56\xcb\x32\xcb\x36\xcd\xae\x24\xd0\x97\xf4\x27\x5b\x15\xdd\x66\xd1\x14\xed\x8a\x12\x9e\xdb\xef\xac\xfc\xb4\xdf\x36\x2d\x03\xfd\x24\xbf\xb2\x4d\xb9\xdd\x73\x19\xfa\x93\x75\xd5\xba\x9e\x57\x35\x7d\x5e\xd2\xaf\xfc\x55\x2d\x29\xcd\xa1\xb7\xa4\xb7\x87\x5e\xd2\x0e\x7b\x4b\xfa\x65\x9f\xb5\xe5\xba\xa2\xde\xb4\x94\xf4\x4e\x7f\x66\x37\xe5\xa2\xab\x7a\x6e\xe9\x4f\xf2\x2b\xfb\x58\xb6\x5d\xd5\x70\xed\x7f\x94\x5f\xd9\xbe\x58\x33\xc0\x05\xfd\xc9\xfa\x72\xb7\xdf\x16\x28\x70\xa5\x3f\xb3\x6d\x51\xaf\x0f\x02\xf3\x5a\x7f\x66\xcb\xb6\xa4\xac\x79\x5d\xde\x50\xea\x19\x3e\x66\xb3\x59\x76\xa0\x49\x98\xef\xdb\xe6\xba\xda\x96\xf3\xa2\x5e\xcd\x77\x32\xcc\x5f\x28\x3d\xd7\xf4\x9c\xd2\x73\x4e\xc7\x10\xca\x15\x0d\x75\x5e\x74\x3a\x0e\x9a\x4b\x1a\x79\xd1\x65\xa8\xaa\x2e\x76\x56\x9a\x7f\x66\xe5\xae\xa8\xb6\x3c\x6b\xfc\x97\xfa\xdd\x75\x37\x0d\xa6\xf6\x42\x7f\xd2\x1c\xcc\xfb\xdb\x7d\x89\x29\x78\x7a\x45\xbf\xb2\x65\xb1\xef\x97\x9b\x82\xbb\x29\xbf\x32\x02\xda\x37\x34\x17\x4d\x7b\x0b\x38\xfb\xc8\x9a\x76\x5d\xd4\xd5\x5f\x8b\x5e\xe6\xe7\xad\xfb\xcc\x76\x55\xdb\x36\x3c\xb5\xe7\xf8\x91\xd1\xc8\xe7\x5c\x0f\xa5\xbc\xa1\x49\x70\xb5\x70\xce\xae\x5a\xb7\x32\x8b\x9c\x79\x8e\x2f\xae\x45\xf2\xb4\x26\xc9\x0a\xb5\x5d\x37\xed\x07\x4d\x7d\xc1\x3f\x07\x55\x52\xe7\x34\x37\xed\x57\x51\xd3\x7a\x68\xee\x39\x3e\x12\x80\x2e\x2b\x56\x3b\x9a\xe1\x7d\x51\x97\x3c\x75\xa7\xfc\x45\xf3\x45\x5f\x59\xb1\x5c\x36\x87\xba\x9f\x77\x65\xdf\x57\xf5\x9a\xd7\xe0\x54\x92\xf2\x4b\x4d\xca\x5c\x5e\x48\xbb\x6d\x0e\x61\x95\x29\xfd\xcf\xf4\x99\x5f\xc8\xa7\xe4\xb9\x42\xc8\x0c\x25\xa9\xc9\xbe\xfa\x58\xf5\x55\x29\x8d\xd9\x47\xb6\x3f\x6c\xb7\x34\x9f\x7f\x39\x94\x5d\xcf\x59\x17\xf4\x4d\x33\x20\xdf\x59\xd5\x75\x07\x94\x78\x85\x1f\x19\x2d\x6a\xbd\xc4\x70\xce\xf0\x23\xcb\x7e\xad\xea\xae\x2f\xb6\xdb\xf7\x99\xfe\x60\x60\xf9\x25\xf3\xd4\x57\x3d\x3a\xab\x89\xf9\x65\x5f\xee\x3b\x9e\xe8\xfc\x45\xd5\x76\xfd\xd3\xbe\x22\x54\x7b\x77\xa8\xb3\x55\xb3\xfc\x40\x48\xcc\x1b\x12\x5b\xe9\xd5\x75\x4e\x63\x7a\x44\x68\xdc\x1e\xea\x9a\x46\x91\xff\xdc\xd0\xc8\xa8\x99\x6a\x55\xe6\xcf\x01\x7d\x92\xef\xb7\x65\xd1\x11\x48\x59\xac\xf2\x6f\x8b\xbc\x2f\xda\x75\xd9\x7f\xf7\x60\xbe\xa0\xcd\xf3\xe1\x41\xbe\x69\xcb\xeb\xef\x1e\x3c\xec\x1e\x7c\xff\xf3\x81\x8a\x6d\xab\xba\xec\xbe\x7d\x56\x7c\x9f\x2f\x0b\xca\xa1\xb1\xde\xe6\x8b\xf2\x9a\xf7\x0a\xb5\x95\x13\x92\xd6\x6b\xde\x27\xb7\xfd\x86\x1b\xa4\x05\xa3\x1f\x5d\xce\x1b\xf5\xab\x8c\x67\x89\x36\xf2\x7c\xb5\x30\xa2\x84\x0e\x21\xb9\xa5\x59\x3a\xbf\xbd\xfc\xf7\xd7\x27\xf9\x05\x51\xa6\x75\x5b\xe2\x37\xfd\x47\x25\xfe\x90\xd3\x68\xaf\xaa\xe7\x3f\xce\x32\x2a\x6b\x13\xf2\xbc\xe8\x8b\x05\xf7\x3d\x2c\x12\x67\xca\x1e\x0a\x79\xd8\x49\x4c\xeb\x40\xd7\xba\x1e\xbb\x53\x77\xe6\xe4\x3e\xa4\x3a\x74\xf3\x86\x3a\xde\xf0\x0e\xa6\xf4\x30\xb3\x17\x32\x67\x54\x55\xfe\xea\xcd\x9b\xb7\xcf\x7f\xcc\xcb\x7a\x4d\x33\x93\xdf\x54\xfd\x26\x3f\xf4\xd7\xff\xff\x7c\x5d\xd6\x65\x5b\x6c\xe7\xcb\x8a\x27\xa5\x25\xbc\xca\x69\x96\x64\x88\xb3\xac\xeb\xb6\x44\x60\x56\xdc\xca\xe5\xe5\xeb\xfc\x9c\x7e\x52\x67\xa8\x2c\x77\xa4\xdf\x64\xdd\x5f\xb6\x3c\x51\xa1\xc1\xab\x4d\x99\x03\x67\x01\xd4\x5c\x0f\xe7\x25\x5f\x69\x5f\x67\xf9\xb7\x8b\xf6\x7b\xd7\xbf\x62\xd1\x35\xdb\x43\xaf\x25\x6f\x36\x65\x8d\x85\x22\x54\x6a\x7b\xa2\x56\x46\xfb\x67\x59\xd9\xb6\x73\xa2\x9b\xfd\x2d\x2f\x8f\xf6\xe5\x58\x2b\x52\x19\xa1\x72\xdd\xf4\xb4\xfc\x39\xca\x49\x15\x55\xfd\xb1\xd8\x56\x2b\x5a\xa4\x38\x91\x69\x59\x24\xae\x1a\x5a\x6f\x2e\x4d\x18\xdd\xdc\x60\x8a\x68\x83\x11\x59\xcf\x1f\xcc\x1e\x80\xce\x3e\x78\xfa\x60\x96\xd5\xcd\x5c\x88\x00\x53\xe4\x55\xd5\x15\x0b\xa2\xce\x72\x5a\xb4\x46\xec\xfe\xcc\x78\x27\x5d\x51\x88\x3c\x81\xe0\x35\xe1\x13\x08\x84\x9f\x91\xb2\x20\x32\x0d\x5a\xa2\x54\xc4\x8f\xdd\x48\x4e\xc0\x0b\xa1\x3a\x21\x61\x34\xe6\xcc\x16\xda\xb0\xf2\x74\xbf\xdf\x56\x4b\x69\xfa\x67\xc9\x8b\x08\xca\xe7\xb1\x4e\x8a\x87\x03\x82\x59\x9e\x43\x33\xea\x35\x53\xa5\x3c\x21\xef\x28\xbf\x29\x69\xc7\x6d\x0e\x6b\x39\x93\xb6\xcd\x61\xf5\x15\x0e\x07\x5b\xb9\x48\x82\xf3\x77\x0d\x75\x18\x58\x15\x00\x62\x13\xa7\x44\x50\x98\x05\x68\xcb\x5d\xd3\xf3\xc4\x69\x31\x26\x73\x37\x15\x65\xd2\x48\xbb\xe2\x23\x1d\x6e\x7d\x23\x5b\x79\x45\x5b\x75\xc9\x15\xcf\x32\x22\x2b\x73\xdd\x4e\x44\x7f\x64\x4b\x59\x5a\x8a\xbb\x80\xda\x1d\x68\x17\x6e\xa8\x32\x9e\x78\xe6\x43\xa8\xca\xa9\x7e\x62\x48\x54\x0f\xa8\x03\xed\xf8\x86\xce\x4c\x5e\xe8\xe7\xf8\xa1\xdf\xbe\x7e\xea\x55\x71\x7d\x4d\xbd\xea\x68\x37\xbd\xcc\x97\xdb\x86\xb6\xe2\x2f\xef\x5e\x77\xbc\xd1\x36\xf3\x7d\xd3\x82\xff\xa0\xac\x0b\xfa\x19\xd2\xdc\x44\x33\x44\x7d\xd8\x2d\xe8\xeb\x66\x53\x2d\x37\x32\xed\x5c\x82\xf7\x0Line truncated
func confLocaleLocale_enUsIniBytes() ([]byte, error) { func confLocaleLocale_enUsIniBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@@ -4382,7 +4382,7 @@ func confLocaleLocale_enUsIni() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 55766, mode: os.FileMode(420), modTime: time.Unix(1472559839, 0)} info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 55979, mode: os.FileMode(420), modTime: time.Unix(1472598262, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
+1 -1
View File
@@ -216,7 +216,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Data["HasAccess"] = true ctx.Data["HasAccess"] = true
if repo.IsMirror { if repo.IsMirror {
ctx.Repo.Mirror, err = models.GetMirror(repo.ID) ctx.Repo.Mirror, err = models.GetMirrorByRepoID(repo.ID)
if err != nil { if err != nil {
ctx.Handle(500, "GetMirror", err) ctx.Handle(500, "GetMirror", err)
return return
+1
View File
@@ -113,6 +113,7 @@ var (
AnsiCharset string AnsiCharset string
ForcePrivate bool ForcePrivate bool
MaxCreationLimit int MaxCreationLimit int
MirrorQueueLength int
PullRequestQueueLength int PullRequestQueueLength int
PreferredLicenses []string PreferredLicenses []string
+1
View File
@@ -75,6 +75,7 @@ func GlobalInit() {
// Booting long running goroutines. // Booting long running goroutines.
cron.NewContext() cron.NewContext()
models.InitSyncMirrors()
models.InitDeliverHooks() models.InitDeliverHooks()
models.InitTestPullRequests() models.InitTestPullRequests()
log.NewGitLogger(path.Join(setting.LogRootPath, "http.log")) log.NewGitLogger(path.Join(setting.LogRootPath, "http.log"))
-1
View File
@@ -490,7 +490,6 @@ func UploadIssueAttachment(ctx *context.Context) {
func ViewIssue(ctx *context.Context) { func ViewIssue(ctx *context.Context) {
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireSimpleMDE"] = true
ctx.Data["RequireDropzone"] = true ctx.Data["RequireDropzone"] = true
renderAttachmentSettings(ctx) renderAttachmentSettings(ctx)
+31 -20
View File
@@ -104,34 +104,42 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
} }
} }
if repo.IsMirror { ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
if isNameChanged { ctx.Redirect(repo.Link() + "/settings")
var err error
ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
if err != nil {
ctx.Handle(500, "RefreshRepositoryMirror", err)
return
}
}
if form.Interval > 0 { case "mirror":
ctx.Repo.Mirror.EnablePrune = form.EnablePrune if !repo.IsMirror {
ctx.Repo.Mirror.Interval = form.Interval ctx.Handle(404, "", nil)
ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour) return
if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil { }
ctx.Handle(500, "UpdateMirror", err)
return if form.Interval > 0 {
} ctx.Repo.Mirror.EnablePrune = form.EnablePrune
} ctx.Repo.Mirror.Interval = form.Interval
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil { ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour)
ctx.Handle(500, "SaveAddress", err) if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
ctx.Handle(500, "UpdateMirror", err)
return return
} }
} }
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
ctx.Handle(500, "SaveAddress", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success")) ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
ctx.Redirect(repo.Link() + "/settings") ctx.Redirect(repo.Link() + "/settings")
case "mirror-sync":
if !repo.IsMirror {
ctx.Handle(404, "", nil)
return
}
go models.MirrorQueue.Add(repo.ID)
ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress"))
ctx.Redirect(repo.Link() + "/settings")
case "advanced": case "advanced":
repo.EnableWiki = form.EnableWiki repo.EnableWiki = form.EnableWiki
repo.EnableExternalWiki = form.EnableExternalWiki repo.EnableExternalWiki = form.EnableExternalWiki
@@ -278,6 +286,9 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success")) ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings") ctx.Redirect(ctx.Repo.RepoLink + "/settings")
default:
ctx.Handle(404, "", nil)
} }
} }
+1 -1
View File
@@ -1 +1 @@
0.9.95.0830 0.9.96.0830
+39 -12
View File
@@ -50,12 +50,26 @@
</div> </div>
</div> </div>
{{end}} {{end}}
{{if .Repository.IsMirror}}
<div class="field">
<button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>
</div>
</form>
</div>
{{if .Repository.IsMirror}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.settings.mirror_settings"}}
</h4>
<div class="ui attached segment">
<form class="ui form" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="mirror">
<div class="inline field {{if .Err_EnablePrune}}error{{end}}"> <div class="inline field {{if .Err_EnablePrune}}error{{end}}">
<label>{{.i18n.Tr "repo.mirror_prune"}}</label> <label>{{.i18n.Tr "repo.mirror_prune"}}</label>
<div class="ui checkbox"> <div class="ui checkbox">
<input id="enable_prune" name="enable_prune" type="checkbox" {{if .MirrorEnablePrune}}checked{{end}}> <input id="enable_prune" name="enable_prune" type="checkbox" {{if .MirrorEnablePrune}}checked{{end}}>
<label>{{.i18n.Tr "repo.mirror_prune_desc"}}</label> <label>{{.i18n.Tr "repo.mirror_prune_desc"}}</label>
</div> </div>
</div> </div>
<div class="inline field {{if .Err_Interval}}error{{end}}"> <div class="inline field {{if .Err_Interval}}error{{end}}">
@@ -64,23 +78,36 @@
</div> </div>
<div class="field"> <div class="field">
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label> <label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}"> <input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required>
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p> <p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>
</div> </div>
{{end}}
<div class="field">
<button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button>
</div>
</form>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="field">
<button class="ui green button">{{$.i18n.Tr "repo.settings.update_settings"}}</button> <form class="ui form" method="post">
</div> {{.CsrfTokenHtml}}
</form> <input type="hidden" name="action" value="mirror-sync">
</div> <div class="inline field">
<label>{{.i18n.Tr "repo.mirror_last_synced"}}</label>
<span>{{.Mirror.Updated}}</span>
</div>
<div class="field">
<button class="ui blue button">{{$.i18n.Tr "repo.settings.sync_mirror"}}</button>
</div>
</form>
</div>
{{end}}
<h4 class="ui top attached header"> <h4 class="ui top attached header">
{{.i18n.Tr "repo.settings.advanced_settings"}} {{.i18n.Tr "repo.settings.advanced_settings"}}
</h4> </h4>
<div class="ui attached segment"> <div class="ui attached segment">
<form class="ui form" action="{{.Link}}" method="post"> <form class="ui form" method="post">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
<input type="hidden" name="action" value="advanced"> <input type="hidden" name="action" value="advanced">