introduce git-shell

This commit is contained in:
Unknwon 2015-11-26 17:33:45 -05:00
parent 2b10fdc4dc
commit c50a3503e6
16 changed files with 155 additions and 135 deletions

View file

@ -17,6 +17,7 @@ github.com/go-sql-driver/mysql = commit:d512f20
github.com/go-xorm/core = commit:3e10003353
github.com/go-xorm/xorm = commit:c643188
github.com/gogits/chardet = commit:2404f77725
github.com/gogits/git-shell =
github.com/gogits/go-gogs-client = commit:7c02c95
github.com/issue9/identicon = commit:5a61672
github.com/klauspost/compress = commit:bbfa9dc

View file

@ -536,7 +536,8 @@ func runWeb(ctx *cli.Context) {
m.Get("/?:page", repo.Wiki)
m.Group("", func() {
m.Get("/_new", repo.NewWiki)
m.Combo("/_new").Get(repo.NewWiki).
Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
m.Get("/:page/_edit", repo.EditWiki)
}, reqSignIn)
}, middleware.RepoRef())

View file

@ -415,12 +415,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
return fmt.Errorf("GetOwner: %v", err)
}
headRepoPath, err := pr.HeadRepo.RepoPath()
if err != nil {
return fmt.Errorf("HeadRepo.RepoPath: %v", err)
}
headGitRepo, err := git.OpenRepository(headRepoPath)
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}

View file

@ -175,12 +175,8 @@ func DeleteReleaseByID(id int64) error {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
repoPath, err := repo.RepoPath()
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
_, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
_, stderr, err := process.ExecDir(-1, repo.RepoPath(),
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
"git", "tag", "-d", rel.TagName)
if err != nil && !strings.Contains(stderr, "not found") {
return fmt.Errorf("git tag -d: %v - %s", err, stderr)

View file

@ -24,11 +24,14 @@ import (
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
"gopkg.in/ini.v1"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/bindata"
"github.com/gogits/gogs/modules/git"
oldgit "github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
@ -95,19 +98,15 @@ func NewRepoContext() {
}
// Check Git version.
ver, err := git.GetVersion()
gitVer, err := git.Version()
if err != nil {
log.Fatal(4, "Fail to get Git version: %v", err)
}
reqVer, err := git.ParseVersion("1.7.1")
if err != nil {
log.Fatal(4, "Fail to parse required Git version: %v", err)
}
if ver.LessThan(reqVer) {
log.Info("Git Version: %s", gitVer)
if version.Compare("1.7.1", gitVer, ">") {
log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1")
}
log.Info("Git Version: %s", ver.String())
// 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"} {
@ -197,6 +196,25 @@ func (repo *Repository) GetOwner() error {
return repo.getOwner(x)
}
func (repo *Repository) mustOwner(e Engine) *User {
if err := repo.getOwner(e); err != nil {
return &User{
Name: "error",
FullName: err.Error(),
}
}
return repo.Owner
}
// MustOwner always returns a valid *User object to avoid
// conceptually impossible error handling.
// It creates a fake object that contains error deftail
// when error occurs.
func (repo *Repository) MustOwner() *User {
return repo.mustOwner(x)
}
// GetAssignees returns all users that have write access of repository.
func (repo *Repository) GetAssignees() (_ []*User, err error) {
if err = repo.GetOwner(); err != nil {
@ -253,30 +271,16 @@ func (repo *Repository) GetBaseRepo() (err error) {
return err
}
func (repo *Repository) repoPath(e Engine) (string, error) {
if err := repo.getOwner(e); err != nil {
return "", err
}
return RepoPath(repo.Owner.Name, repo.Name), nil
func (repo *Repository) repoPath(e Engine) string {
return RepoPath(repo.mustOwner(e).Name, repo.Name)
}
func (repo *Repository) RepoPath() (string, error) {
func (repo *Repository) RepoPath() string {
return repo.repoPath(x)
}
func (repo *Repository) WikiPath() (string, error) {
if err := repo.GetOwner(); err != nil {
return "", err
}
return WikiPath(repo.Owner.Name, repo.Name), nil
}
func (repo *Repository) RepoLink() (string, error) {
if err := repo.GetOwner(); err != nil {
return "", err
}
return setting.AppSubUrl + "/" + repo.Owner.Name + "/" + repo.Name, nil
func (repo *Repository) RepoLink() string {
return setting.AppSubUrl + "/" + repo.MustOwner().Name + "/" + repo.Name
}
func (repo *Repository) HasAccess(u *User) bool {
@ -315,11 +319,7 @@ func (repo *Repository) LocalCopyPath() string {
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
repoPath, err := repo.RepoPath()
if err != nil {
return err
}
repoPath := repo.RepoPath()
localPath := repo.LocalCopyPath()
if !com.IsExist(localPath) {
_, stderr, err := process.Exec(
@ -399,7 +399,7 @@ func (repo *Repository) CloneLink() (cl CloneLink, err error) {
var (
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
reservedPatterns = []string{"*.git", "*.keys"}
reservedPatterns = []string{"*.git", "*.keys", "*.wiki"}
)
// IsUsableName checks if name is reserved or pattern of name is not allowed.
@ -569,7 +569,7 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
// Check if repository has master branch, if so set it to default branch.
gitRepo, err := git.OpenRepository(repoPath)
gitRepo, err := oldgit.OpenRepository(repoPath)
if err != nil {
return repo, fmt.Errorf("open git repository: %v", err)
}
@ -581,7 +581,7 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
// initRepoCommit temporarily changes with work directory.
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
var stderr string
if _, stderr, err = process.ExecDir(-1,
tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath),
@ -885,11 +885,6 @@ func RepoPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
}
// WikiPath returns wiki data path by given user and repository name.
func WikiPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
}
// TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
newOwner, err := GetUserByName(newOwnerName)
@ -1177,10 +1172,7 @@ func DeleteRepository(uid, repoID int64) error {
}
// Remove repository files.
repoPath, err := repo.repoPath(sess)
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
repoPath := repo.repoPath(sess)
if err = os.RemoveAll(repoPath); err != nil {
desc := fmt.Sprintf("delete repository files[%s]: %v", repoPath, err)
log.Warn(desc)
@ -1328,14 +1320,7 @@ func DeleteRepositoryArchives() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
return os.RemoveAll(filepath.Join(repoPath, "archives"))
return os.RemoveAll(filepath.Join(repo.RepoPath(), "archives"))
})
}
@ -1345,15 +1330,7 @@ func DeleteMissingRepositories() error {
if err := x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
if !com.IsDir(repoPath) {
if !com.IsDir(repo.RepoPath()) {
repos = append(repos, repo)
}
return nil
@ -1384,14 +1361,7 @@ func RewriteRepositoryUpdateHook() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
if err2 := CreateRepositoryNotice(fmt.Sprintf("RewriteRepositoryUpdateHook[%d]: %v", repo.ID, err)); err2 != nil {
log.Error(4, "CreateRepositoryNotice: %v", err2)
}
return nil
}
return createUpdateHook(repoPath)
return createUpdateHook(repo.RepoPath())
})
}
@ -1458,11 +1428,7 @@ func MirrorUpdate() {
return nil
}
repoPath, err := m.Repo.RepoPath()
if err != nil {
return fmt.Errorf("Repo.RepoPath: %v", err)
}
repoPath := m.Repo.RepoPath()
if _, stderr, err := process.ExecDir(10*time.Minute,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update", "--prune"); err != nil {
@ -1502,12 +1468,8 @@ func GitFsck() {
if err := x.Where("id>0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
repoPath, err := repo.RepoPath()
if err != nil {
return fmt.Errorf("RepoPath: %v", err)
}
_, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
repoPath := repo.RepoPath()
_, _, 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)
@ -1925,15 +1887,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
return nil, err
}
oldRepoPath, err := oldRepo.RepoPath()
if err != nil {
return nil, fmt.Errorf("get old repository path: %v", err)
}
repoPath := RepoPath(u.Name, repo.Name)
_, stderr, err := process.ExecTimeout(10*time.Minute,
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
"git", "clone", "--bare", oldRepoPath, repoPath)
"git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
if err != nil {
return nil, fmt.Errorf("git clone: %v", stderr)
}

56
models/wiki.go Normal file
View file

@ -0,0 +1,56 @@
// 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 (
"fmt"
"path/filepath"
"strings"
"github.com/Unknwon/com"
"github.com/gogits/git-shell"
)
// ToWikiPageName formats a string to corresponding wiki URL name.
func ToWikiPageName(name string) string {
return strings.Replace(name, " ", "-", -1)
}
// WikiPath returns wiki data path by given user and repository name.
func WikiPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
}
func (repo *Repository) WikiPath() string {
return WikiPath(repo.MustOwner().Name, repo.Name)
}
// HasWiki returns true if repository has wiki.
func (repo *Repository) HasWiki() bool {
return com.IsDir(repo.WikiPath())
}
// InitWiki initializes a wiki for repository,
// it does nothing when repository already has wiki.
func (repo *Repository) InitWiki() error {
if repo.HasWiki() {
return nil
}
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
}
return nil
}
// AddWikiPage adds new page to repository wiki.
func (repo *Repository) AddWikiPage(title, content, message string) (err error) {
if err = repo.InitWiki(); err != nil {
return fmt.Errorf("InitWiki: %v", err)
}
return nil
}

View file

@ -237,3 +237,21 @@ type EditReleaseForm struct {
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __ __.__ __ .__
// / \ / \__| | _|__|
// \ \/\/ / | |/ / |
// \ /| | <| |
// \__/\ / |__|__|_ \__|
// \/ \/
type NewWikiForm struct {
Title string `binding:"Required"`
Content string
Message string
}
// FIXME: use code generation to generate this method.
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -311,11 +311,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
return
}
ctx.Repo.GitRepo = gitRepo
ctx.Repo.RepoLink, err = repo.RepoLink()
if err != nil {
ctx.Handle(500, "RepoLink", err)
return
}
ctx.Repo.RepoLink = repo.RepoLink()
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name

View file

@ -113,7 +113,8 @@ func Remove(pid int64) {
func Kill(pid int64) error {
for i, proc := range Processes {
if proc.Pid == pid {
if proc.Cmd.Process != nil && proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
if proc.Cmd != nil && proc.Cmd.Process != nil &&
proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
if err := proc.Cmd.Process.Kill(); err != nil {
return fmt.Errorf("fail to kill process(%d/%s): %v", proc.Pid, proc.Description, err)
}

View file

@ -17,6 +17,8 @@ import (
"gopkg.in/ini.v1"
"gopkg.in/macaron.v1"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/models/cron"
"github.com/gogits/gogs/modules/auth"
@ -39,6 +41,7 @@ func checkRunMode() {
macaron.Env = macaron.PROD
macaron.ColorLog = false
setting.ProdMode = true
git.Debug = false
}
log.Info("Run Mode: %s", strings.Title(macaron.Env))
}

View file

@ -31,7 +31,7 @@ import (
func authRequired(ctx *middleware.Context) {
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
ctx.HTML(401, base.TplName("status/401"))
ctx.Error(401)
}
func HTTP(ctx *middleware.Context) {

View file

@ -210,13 +210,7 @@ func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullR
}
if pull.HeadRepo != nil {
headRepoPath, err := pull.HeadRepo.RepoPath()
if err != nil {
ctx.Handle(500, "HeadRepo.RepoPath", err)
return nil
}
headGitRepo, err = git.OpenRepository(headRepoPath)
headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
if err != nil {
ctx.Handle(500, "OpenRepository", err)
return nil
@ -496,11 +490,7 @@ func PrepareCompareDiff(
)
// Get diff information.
ctx.Data["CommitRepoLink"], err = headRepo.RepoLink()
if err != nil {
ctx.Handle(500, "RepoLink", err)
return false
}
ctx.Data["CommitRepoLink"] = headRepo.RepoLink()
headCommitID, err := headGitRepo.GetCommitIdOfBranch(headBranch)
if err != nil {

View file

@ -5,9 +5,8 @@
package repo
import (
"github.com/Unknwon/com"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
)
@ -22,8 +21,7 @@ func Wiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
ctx.Data["PageIsWiki"] = true
wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
if !com.IsDir(wikiPath) {
if !ctx.Repo.Repository.HasWiki() {
ctx.HTML(200, WIKI_START)
return
}
@ -36,14 +34,31 @@ func NewWiki(ctx *middleware.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
if !com.IsDir(wikiPath) {
if !ctx.Repo.Repository.HasWiki() {
ctx.Data["title"] = "Home"
}
ctx.HTML(200, WIKI_NEW)
}
func NewWikiPost(ctx *middleware.Context, form auth.NewWikiForm) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
if ctx.HasError() {
ctx.HTML(200, WIKI_NEW)
return
}
if err := ctx.Repo.Repository.AddWikiPage(form.Title, form.Content, form.Message); err != nil {
ctx.Handle(500, "AddWikiPage", err)
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageName(form.Title))
}
func EditWiki(ctx *middleware.Context) {
ctx.PlainText(200, []byte(ctx.Params(":page")))
}

View file

@ -7,8 +7,9 @@
{{.i18n.Tr "repo.wiki.new_page"}}
</div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<div class="field">
<input name="title" value="{{.title}}" autofocus>
<input name="title" value="{{.title}}" autofocus required>
</div>
<div class="field">
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea>

View file

@ -1,5 +0,0 @@
{{template "base/head" .}}
<div class="ui container center">
401 Unauthorized
</div>
{{template "base/footer" .}}

View file

@ -1,5 +0,0 @@
{{template "base/head" .}}
<div class="ui container center">
403 Forbidden
</div>
{{template "base/footer" .}}