| @@ -5,7 +5,7 @@ Gogs - Go Git Service [ |  | ||||
| ##### Current version: 0.6.16 Beta | |||||
| ##### Current version: 0.6.18 Beta | |||||
| <table> | <table> | ||||
| <tr> | <tr> | ||||
| @@ -11,7 +11,11 @@ RUN_MODE = dev | |||||
| [repository] | [repository] | ||||
| ROOT = | ROOT = | ||||
| SCRIPT_TYPE = bash | SCRIPT_TYPE = bash | ||||
| ; Patch test queue length, make it as large as possible. | |||||
| ; Default ANSI charset | |||||
| ANSI_CHARSET = | |||||
| ; Force every new repository to be private | |||||
| FORCE_PRIVATE = false | |||||
| ; Patch test queue length, make it as large as possible | |||||
| PULL_REQUEST_QUEUE_LENGTH = 10000 | PULL_REQUEST_QUEUE_LENGTH = 10000 | ||||
| [ui] | [ui] | ||||
| @@ -334,6 +334,7 @@ repo_name = Repository Name | |||||
| repo_name_helper = A good repository name is usually composed of short, memorable and unique keywords. | repo_name_helper = A good repository name is usually composed of short, memorable and unique keywords. | ||||
| visibility = Visibility | visibility = Visibility | ||||
| visiblity_helper = This repository is <span class="ui red text">Private</span> | visiblity_helper = This repository is <span class="ui red text">Private</span> | ||||
| visiblity_helper_forced = Site admin has forced all new repositories to be <span class="ui red text">Private</span> | |||||
| visiblity_fork_helper = (Change of this value will affect all forks) | visiblity_fork_helper = (Change of this value will affect all forks) | ||||
| fork_repo = Fork Repository | fork_repo = Fork Repository | ||||
| fork_from = Fork From | fork_from = Fork From | ||||
| @@ -334,6 +334,7 @@ repo_name=仓库名称 | |||||
| repo_name_helper=伟大的仓库名称一般都较短、令人深刻并且 <strong>独一无二</strong> 的。 | repo_name_helper=伟大的仓库名称一般都较短、令人深刻并且 <strong>独一无二</strong> 的。 | ||||
| visibility=可见性 | visibility=可见性 | ||||
| visiblity_helper=该仓库为 <span class="ui red text">私有的</span> | visiblity_helper=该仓库为 <span class="ui red text">私有的</span> | ||||
| visiblity_helper_forced=网站管理员已强制要求所有新建仓库必须为 <span class="ui red text">私有的</span> | |||||
| visiblity_fork_helper=(修改该值将会影响到所有派生仓库) | visiblity_fork_helper=(修改该值将会影响到所有派生仓库) | ||||
| fork_repo=派生仓库 | fork_repo=派生仓库 | ||||
| fork_from=派生自 | fork_from=派生自 | ||||
| @@ -17,7 +17,7 @@ import ( | |||||
| "github.com/gogits/gogs/modules/setting" | "github.com/gogits/gogs/modules/setting" | ||||
| ) | ) | ||||
| const APP_VER = "0.6.17.1025 Beta" | |||||
| const APP_VER = "0.6.18.1025 Beta" | |||||
| func init() { | func init() { | ||||
| runtime.GOMAXPROCS(runtime.NumCPU()) | runtime.GOMAXPROCS(runtime.NumCPU()) | ||||
| @@ -480,13 +480,21 @@ func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) er | |||||
| return nil | return nil | ||||
| } | } | ||||
| type MigrateRepoOptions struct { | |||||
| Name string | |||||
| Description string | |||||
| IsPrivate bool | |||||
| IsMirror bool | |||||
| RemoteAddr string | |||||
| } | |||||
| // MigrateRepository migrates a existing repository from other project hosting. | // MigrateRepository migrates a existing repository from other project hosting. | ||||
| func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) { | |||||
| func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { | |||||
| repo, err := CreateRepository(u, CreateRepoOptions{ | repo, err := CreateRepository(u, CreateRepoOptions{ | ||||
| Name: name, | |||||
| Description: desc, | |||||
| IsPrivate: private, | |||||
| IsMirror: mirror, | |||||
| Name: opts.Name, | |||||
| Description: opts.Description, | |||||
| IsPrivate: opts.IsPrivate, | |||||
| IsMirror: opts.IsMirror, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -496,7 +504,7 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str | |||||
| tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond())) | tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond())) | ||||
| os.MkdirAll(tmpDir, os.ModePerm) | os.MkdirAll(tmpDir, os.ModePerm) | ||||
| repoPath := RepoPath(u.Name, name) | |||||
| repoPath := RepoPath(u.Name, opts.Name) | |||||
| if u.IsOrganization() { | if u.IsOrganization() { | ||||
| t, err := u.GetOwnerTeam() | t, err := u.GetOwnerTeam() | ||||
| @@ -509,8 +517,8 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str | |||||
| } | } | ||||
| repo.IsBare = false | repo.IsBare = false | ||||
| if mirror { | |||||
| if err = MirrorRepository(repo.ID, u.Name, repo.Name, repoPath, url); err != nil { | |||||
| if opts.IsMirror { | |||||
| if err = MirrorRepository(repo.ID, u.Name, repo.Name, repoPath, opts.RemoteAddr); err != nil { | |||||
| return repo, err | return repo, err | ||||
| } | } | ||||
| repo.IsMirror = true | repo.IsMirror = true | ||||
| @@ -522,7 +530,7 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str | |||||
| // FIXME: this command could for both migrate and mirror | // FIXME: this command could for both migrate and mirror | ||||
| _, stderr, err := process.ExecTimeout(10*time.Minute, | _, stderr, err := process.ExecTimeout(10*time.Minute, | ||||
| fmt.Sprintf("MigrateRepository: %s", repoPath), | fmt.Sprintf("MigrateRepository: %s", repoPath), | ||||
| "git", "clone", "--mirror", "--bare", "--quiet", url, repoPath) | |||||
| "git", "clone", "--mirror", "--bare", "--quiet", opts.RemoteAddr, repoPath) | |||||
| if err != nil { | if err != nil { | ||||
| return repo, fmt.Errorf("git clone --mirror --bare --quiet: %v", stderr) | return repo, fmt.Errorf("git clone --mirror --bare --quiet: %v", stderr) | ||||
| } else if err = createUpdateHook(repoPath); err != nil { | } else if err = createUpdateHook(repoPath); err != nil { | ||||
| @@ -71,7 +71,7 @@ type User struct { | |||||
| Created time.Time `xorm:"CREATED"` | Created time.Time `xorm:"CREATED"` | ||||
| Updated time.Time `xorm:"UPDATED"` | Updated time.Time `xorm:"UPDATED"` | ||||
| // Remember visibility choice for convenience. | |||||
| // Remember visibility choice for convenience, true for private | |||||
| LastRepoVisibility bool | LastRepoVisibility bool | ||||
| // Permissions. | // Permissions. | ||||
| @@ -59,8 +59,8 @@ func ShortSha(sha1 string) string { | |||||
| func DetectEncoding(content []byte) (string, error) { | func DetectEncoding(content []byte) (string, error) { | ||||
| detector := chardet.NewTextDetector() | detector := chardet.NewTextDetector() | ||||
| result, err := detector.DetectBest(content) | result, err := detector.DetectBest(content) | ||||
| if result.Charset != "UTF-8" && len(setting.AnsiCharset) > 0 { | |||||
| return setting.AnsiCharset, err | |||||
| if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { | |||||
| return setting.Repository.AnsiCharset, err | |||||
| } | } | ||||
| return result.Charset, err | return result.Charset, err | ||||
| } | } | ||||
| @@ -87,11 +87,12 @@ var ( | |||||
| // Repository settings. | // Repository settings. | ||||
| Repository struct { | Repository struct { | ||||
| AnsiCharset string | |||||
| ForcePrivate bool | |||||
| PullRequestQueueLength int | PullRequestQueueLength int | ||||
| } | } | ||||
| RepoRootPath string | RepoRootPath string | ||||
| ScriptType string | ScriptType string | ||||
| AnsiCharset string | |||||
| // UI settings. | // UI settings. | ||||
| ExplorePagingNum int | ExplorePagingNum int | ||||
| @@ -360,7 +361,6 @@ func NewContext() { | |||||
| homeDir = strings.Replace(homeDir, "\\", "/", -1) | homeDir = strings.Replace(homeDir, "\\", "/", -1) | ||||
| sec = Cfg.Section("repository") | sec = Cfg.Section("repository") | ||||
| Repository.PullRequestQueueLength = sec.Key("PULL_REQUEST_QUEUE_LENGTH").MustInt(10000) | |||||
| RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories")) | RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories")) | ||||
| forcePathSeparator(RepoRootPath) | forcePathSeparator(RepoRootPath) | ||||
| if !filepath.IsAbs(RepoRootPath) { | if !filepath.IsAbs(RepoRootPath) { | ||||
| @@ -369,7 +369,9 @@ func NewContext() { | |||||
| RepoRootPath = path.Clean(RepoRootPath) | RepoRootPath = path.Clean(RepoRootPath) | ||||
| } | } | ||||
| ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") | ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") | ||||
| AnsiCharset = sec.Key("ANSI_CHARSET").MustString("") | |||||
| Repository.AnsiCharset = sec.Key("ANSI_CHARSET").String() | |||||
| Repository.ForcePrivate = sec.Key("FORCE_PRIVATE").MustBool() | |||||
| Repository.PullRequestQueueLength = sec.Key("PULL_REQUEST_QUEUE_LENGTH").MustInt(10000) | |||||
| // UI settings. | // UI settings. | ||||
| sec = Cfg.Section("ui") | sec = Cfg.Section("ui") | ||||
| @@ -237,7 +237,13 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||||
| return | return | ||||
| } | } | ||||
| repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) | |||||
| repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{ | |||||
| Name: form.RepoName, | |||||
| Description: form.Description, | |||||
| IsPrivate: form.Private || setting.Repository.ForcePrivate, | |||||
| IsMirror: form.Mirror, | |||||
| RemoteAddr: remoteAddr, | |||||
| }) | |||||
| if err != nil { | if err != nil { | ||||
| if repo != nil { | if repo != nil { | ||||
| if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { | if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { | ||||
| @@ -46,7 +46,7 @@ func checkContextUser(ctx *middleware.Context, uid int64) *models.User { | |||||
| } | } | ||||
| if err != nil { | if err != nil { | ||||
| ctx.Handle(500, "checkContextUser", fmt.Errorf("GetUserById(%d): %v", uid, err)) | |||||
| ctx.Handle(500, "GetUserByID", fmt.Errorf("[%d]: %v", uid, err)) | |||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -67,6 +67,7 @@ func Create(ctx *middleware.Context) { | |||||
| ctx.Data["Readmes"] = models.Readmes | ctx.Data["Readmes"] = models.Readmes | ||||
| ctx.Data["readme"] = "Default" | ctx.Data["readme"] = "Default" | ||||
| ctx.Data["private"] = ctx.User.LastRepoVisibility | ctx.Data["private"] = ctx.User.LastRepoVisibility | ||||
| ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate | |||||
| ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) | ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) | ||||
| if ctx.Written() { | if ctx.Written() { | ||||
| @@ -117,11 +118,11 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| Gitignores: form.Gitignores, | Gitignores: form.Gitignores, | ||||
| License: form.License, | License: form.License, | ||||
| Readme: form.Readme, | Readme: form.Readme, | ||||
| IsPrivate: form.Private, | |||||
| IsPrivate: form.Private || setting.Repository.ForcePrivate, | |||||
| AutoInit: form.AutoInit, | AutoInit: form.AutoInit, | ||||
| }) | }) | ||||
| if err == nil { | if err == nil { | ||||
| log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name) | |||||
| log.Trace("Repository created[%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ||||
| return | return | ||||
| } | } | ||||
| @@ -138,6 +139,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||||
| func Migrate(ctx *middleware.Context) { | func Migrate(ctx *middleware.Context) { | ||||
| ctx.Data["Title"] = ctx.Tr("new_migrate") | ctx.Data["Title"] = ctx.Tr("new_migrate") | ||||
| ctx.Data["private"] = ctx.User.LastRepoVisibility | ctx.Data["private"] = ctx.User.LastRepoVisibility | ||||
| ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate | |||||
| ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) | ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) | ||||
| if ctx.Written() { | if ctx.Written() { | ||||
| @@ -185,9 +187,15 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||||
| return | return | ||||
| } | } | ||||
| repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) | |||||
| repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{ | |||||
| Name: form.RepoName, | |||||
| Description: form.Description, | |||||
| IsPrivate: form.Private || setting.Repository.ForcePrivate, | |||||
| IsMirror: form.Mirror, | |||||
| RemoteAddr: remoteAddr, | |||||
| }) | |||||
| if err == nil { | if err == nil { | ||||
| log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) | |||||
| log.Trace("Repository migrated[%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName) | |||||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) | ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1 +1 @@ | |||||
| 0.6.17.1025 Beta | |||||
| 0.6.18.1025 Beta | |||||
| @@ -41,8 +41,13 @@ | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label>{{.i18n.Tr "repo.visibility"}}</label> | <label>{{.i18n.Tr "repo.visibility"}}</label> | ||||
| <div class="ui checkbox"> | <div class="ui checkbox"> | ||||
| {{if .IsForcedPrivate}} | |||||
| <input name="private" type="checkbox" checked readonly> | |||||
| <label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label> | |||||
| {{else}} | |||||
| <input name="private" type="checkbox" {{if .private}}checked{{end}}> | <input name="private" type="checkbox" {{if .private}}checked{{end}}> | ||||
| <label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> | <label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> | ||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="inline field {{if .Err_Description}}error{{end}}"> | <div class="inline field {{if .Err_Description}}error{{end}}"> | ||||
| @@ -65,8 +65,13 @@ | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label>{{.i18n.Tr "repo.visibility"}}</label> | <label>{{.i18n.Tr "repo.visibility"}}</label> | ||||
| <div class="ui checkbox"> | <div class="ui checkbox"> | ||||
| {{if .IsForcedPrivate}} | |||||
| <input name="private" type="checkbox" checked readonly> | |||||
| <label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label> | |||||
| {{else}} | |||||
| <input name="private" type="checkbox" {{if .private}}checked{{end}}> | <input name="private" type="checkbox" {{if .private}}checked{{end}}> | ||||
| <label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> | <label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> | ||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="inline field"> | <div class="inline field"> | ||||