wiki: finish new

This commit is contained in:
Unknwon 2015-11-27 00:24:24 -05:00
parent c50a3503e6
commit 392f3ee210
15 changed files with 474 additions and 2236 deletions

View file

@ -534,6 +534,7 @@ func runWeb(ctx *cli.Context) {
m.Group("/wiki", func() {
m.Get("/?:page", repo.Wiki)
m.Get("/_list", repo.WikiList)
m.Group("", func() {
m.Combo("/_new").Get(repo.NewWiki).

View file

@ -542,6 +542,7 @@ wiki.create_first_page = Create the first page
wiki.new_page = Create New Page
wiki.default_commit_message = Write a note about this update (optional).
wiki.save_page = Save Page
wiki.last_commit_info = %s edited this page %s
settings = Settings
settings.options = Options

File diff suppressed because it is too large Load diff

View file

@ -51,6 +51,10 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
}
func init() {
git.GetVersion()
}
func createTag(gitRepo *git.Repository, rel *Release) error {
// Only actual create when publish.
if !rel.IsDraft {

View file

@ -31,7 +31,6 @@ import (
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/bindata"
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"
@ -317,27 +316,24 @@ func (repo *Repository) LocalCopyPath() string {
return path.Join(setting.AppDataPath, "tmp/local", com.ToStr(repo.ID))
}
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
repoPath := repo.RepoPath()
localPath := repo.LocalCopyPath()
func updateLocalCopy(repoPath, localPath string) error {
if !com.IsExist(localPath) {
_, stderr, err := process.Exec(
fmt.Sprintf("UpdateLocalCopy(git clone): %s", repoPath), "git", "clone", repoPath, localPath)
if err != nil {
return fmt.Errorf("git clone: %v - %s", err, stderr)
if err := git.Clone(repoPath, localPath); err != nil {
return fmt.Errorf("Clone: %v", err)
}
} else {
_, stderr, err := process.ExecDir(-1, localPath,
fmt.Sprintf("UpdateLocalCopy(git pull --all): %s", repoPath), "git", "pull", "--all")
if err != nil {
return fmt.Errorf("git pull: %v - %s", err, stderr)
if err := git.Pull(localPath, true); err != nil {
return fmt.Errorf("Pull: %v", err)
}
}
return nil
}
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
return updateLocalCopy(repo.RepoPath(), repo.LocalCopyPath())
}
// PatchPath returns corresponding patch file path of repository by given issue ID.
func (repo *Repository) PatchPath(index int64) (string, error) {
if err := repo.GetOwner(); err != nil {
@ -471,6 +467,11 @@ func UpdateMirror(m *Mirror) error {
return updateMirror(x, m)
}
func createUpdateHook(repoPath string) error {
return git.SetUpdateHook(repoPath,
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
}
// MirrorRepository creates a mirror repository from source.
func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
_, stderr, err := process.ExecTimeout(10*time.Minute,
@ -568,20 +569,26 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
}
// Check if repository has master branch, if so set it to default branch.
gitRepo, err := oldgit.OpenRepository(repoPath)
// Try to get HEAD branch and set it as default branch.
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return repo, fmt.Errorf("open git repository: %v", err)
log.Error(4, "OpenRepository: %v", err)
return repo, nil
}
if gitRepo.IsBranchExist("master") {
repo.DefaultBranch = "master"
headBranch, err := gitRepo.GetHEADBranch()
if err != nil {
log.Error(4, "GetHEADBranch: %v", err)
return repo, nil
}
if headBranch != nil {
repo.DefaultBranch = headBranch.Name
}
return repo, UpdateRepository(repo, false)
}
// initRepoCommit temporarily changes with work directory.
func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
var stderr string
if _, stderr, err = process.ExecDir(-1,
tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath),
@ -604,13 +611,6 @@ func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
return nil
}
func createUpdateHook(repoPath string) error {
hookPath := path.Join(repoPath, "hooks/update")
os.MkdirAll(path.Dir(hookPath), os.ModePerm)
return ioutil.WriteFile(hookPath,
[]byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)), 0777)
}
type CreateRepoOptions struct {
Name string
Description string
@ -699,22 +699,17 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
}
// InitRepository initializes README and .gitignore if needed.
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) error {
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) (err error) {
// Somehow the directory could exist.
if com.IsExist(repoPath) {
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
}
// Init bare new repository.
os.MkdirAll(repoPath, os.ModePerm)
_, stderr, err := process.ExecDir(-1, repoPath,
fmt.Sprintf("initRepository (git init --bare): %s", repoPath), "git", "init", "--bare")
if err != nil {
return fmt.Errorf("git init --bare: %v - %s", err, stderr)
}
if err := createUpdateHook(repoPath); err != nil {
return err
if err = git.InitRepository(repoPath, true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
} else if err = createUpdateHook(repoPath); err != nil {
return fmt.Errorf("createUpdateHook: %v", err)
}
tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))

View file

@ -25,9 +25,11 @@ import (
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
oldgit "github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@ -938,11 +940,11 @@ func MakeEmailPrimary(email *EmailAddress) error {
// UserCommit represents a commit with validation of user.
type UserCommit struct {
User *User
*git.Commit
*oldgit.Commit
}
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
func ValidateCommitWithEmail(c *git.Commit) *User {
func ValidateCommitWithEmail(c *oldgit.Commit) *User {
u, err := GetUserByEmail(c.Author.Email)
if err != nil {
return nil
@ -959,7 +961,7 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
e = oldCommits.Front()
)
for e != nil {
c := e.Value.(*git.Commit)
c := e.Value.(*oldgit.Commit)
if v, ok := emails[c.Author.Email]; !ok {
u, _ = GetUserByEmail(c.Author.Email)

View file

@ -6,19 +6,72 @@ package models
import (
"fmt"
"io/ioutil"
"path"
"path/filepath"
"strings"
"sync"
"github.com/Unknwon/com"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/modules/setting"
)
// ToWikiPageName formats a string to corresponding wiki URL name.
func ToWikiPageName(name string) string {
// workingPool represents a pool of working status which makes sure
// that only one instance of same task is performing at a time.
// However, different type of tasks can performing at the same time.
type workingPool struct {
lock sync.Mutex
pool map[string]*sync.Mutex
count map[string]int
}
// CheckIn checks in a task and waits if others are running.
func (p *workingPool) CheckIn(name string) {
p.lock.Lock()
lock, has := p.pool[name]
if !has {
lock = &sync.Mutex{}
p.pool[name] = lock
}
p.count[name]++
p.lock.Unlock()
lock.Lock()
}
// CheckOut checks out a task to let other tasks run.
func (p *workingPool) CheckOut(name string) {
p.lock.Lock()
defer p.lock.Unlock()
p.pool[name].Unlock()
if p.count[name] == 1 {
delete(p.pool, name)
delete(p.count, name)
} else {
p.count[name]--
}
}
var wikiWorkingPool = &workingPool{
pool: make(map[string]*sync.Mutex),
count: make(map[string]int),
}
// ToWikiPageURL formats a string to corresponding wiki URL name.
func ToWikiPageURL(name string) string {
return strings.Replace(name, " ", "-", -1)
}
// ToWikiPageName formats a URL back to corresponding wiki page 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")
@ -46,11 +99,56 @@ func (repo *Repository) InitWiki() error {
return nil
}
func (repo *Repository) LocalWikiPath() string {
return path.Join(setting.AppDataPath, "tmp/local-wiki", com.ToStr(repo.ID))
}
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
func (repo *Repository) UpdateLocalWiki() error {
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
}
// AddWikiPage adds new page to repository wiki.
func (repo *Repository) AddWikiPage(title, content, message string) (err error) {
func (repo *Repository) AddWikiPage(doer *User, title, content, message string) (err error) {
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
if err = repo.InitWiki(); err != nil {
return fmt.Errorf("InitWiki: %v", err)
}
localPath := repo.LocalWikiPath()
// Discard local commits make sure even to remote when local copy exists.
if com.IsExist(localPath) {
// No need to check if nothing in the repository.
if git.IsBranchExist(localPath, "master") {
if err = git.Reset(localPath, true, "origin/master"); err != nil {
return fmt.Errorf("Reset: %v", err)
}
}
}
if err = repo.UpdateLocalWiki(); err != nil {
return fmt.Errorf("UpdateLocalWiki: %v", err)
}
title = strings.Replace(title, "/", " ", -1)
filename := path.Join(localPath, title+".md")
if err = ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
return fmt.Errorf("WriteFile: %v", err)
}
if len(message) == 0 {
message = "Update page '" + title + "'"
}
if err = git.AddChanges(localPath, true); err != nil {
return fmt.Errorf("AddChanges: %v", err)
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
return fmt.Errorf("CommitChanges: %v", err)
} else if err = git.Push(localPath, "origin", "master"); err != nil {
return fmt.Errorf("Push: %v", err)
}
return nil
}

View file

@ -247,7 +247,7 @@ func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
type NewWikiForm struct {
Title string `binding:"Required"`
Content string
Content string `binding:"Required"`
Message string
}

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{
"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit",
"creatorBuild": "19102",
"creatorBuild": "19076",
"files": {
"\/css\/dropzone-4.2.0.css": {
"fileType": 16,
@ -616,18 +616,10 @@
"active": 0,
"flagValue": -1
},
"no_nested_string_interpolation": {
"active": 1,
"flagValue": -1
},
"no_plusplus": {
"active": 0,
"flagValue": -1
},
"no_private_function_fat_arrows": {
"active": 1,
"flagValue": -1
},
"no_stand_alone_at": {
"active": 1,
"flagValue": -1
@ -636,10 +628,6 @@
"active": 1,
"flagValue": -1
},
"no_this": {
"active": 0,
"flagValue": -1
},
"no_throwing_strings": {
"active": 1,
"flagValue": -1

View file

@ -2531,6 +2531,20 @@ footer .container .links > *:first-child {
.repository.wiki.new .editor-preview {
background-color: white;
}
.repository.wiki.view .ui.sub.header {
text-transform: none;
}
.repository.wiki.view .markdown {
padding: 15px 30px;
}
.repository.wiki.view .markdown h1:first-of-type,
.repository.wiki.view .markdown h2:first-of-type,
.repository.wiki.view .markdown h3:first-of-type,
.repository.wiki.view .markdown h4:first-of-type,
.repository.wiki.view .markdown h5:first-of-type,
.repository.wiki.view .markdown h6:first-of-type {
margin-top: 0;
}
.repository.settings.collaboration .collaborator.list {
padding: 0;
}

View file

@ -970,6 +970,24 @@
background-color: white;
}
}
&.view {
.header:not(.sub) {
// padding-left: 30px;
}
.ui.sub.header {
text-transform: none;
}
.markdown {
padding: 15px 30px;
h1, h2, h3, h4, h5, h6 {
&:first-of-type {
margin-top: 0;
}
}
}
}
}
&.settings {

View file

@ -5,6 +5,10 @@
package repo
import (
"io/ioutil"
"github.com/gogits/git-shell"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
@ -18,17 +22,68 @@ const (
)
func Wiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
ctx.Data["PageIsWiki"] = true
if !ctx.Repo.Repository.HasWiki() {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
ctx.HTML(200, WIKI_START)
return
}
wikiRepo, err := git.OpenRepository(ctx.Repo.Repository.WikiPath())
if err != nil {
ctx.Handle(500, "OpenRepository", err)
return
}
commit, err := wikiRepo.GetCommitOfBranch("master")
if err != nil {
ctx.Handle(500, "GetCommitOfBranch", err)
return
}
page := models.ToWikiPageName(ctx.Params(":page"))
if len(page) == 0 {
page = "Home"
}
ctx.Data["Title"] = page
ctx.Data["RequireHighlightJS"] = true
blob, err := commit.GetBlobByPath(page + ".md")
if err != nil {
if git.IsErrNotExist(err) {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_list")
} else {
ctx.Handle(500, "GetBlobByPath", err)
}
return
}
r, err := blob.Data()
if err != nil {
ctx.Handle(500, "Data", err)
return
}
data, err := ioutil.ReadAll(r)
if err != nil {
ctx.Handle(500, "ReadAll", err)
return
}
ctx.Data["Content"] = string(base.RenderMarkdown(data, ctx.Repo.RepoLink))
// Get last change information.
lastCommit, err := wikiRepo.GetCommitByPath(page + ".md")
if err != nil {
ctx.Handle(500, "GetCommitByPath", err)
return
}
ctx.Data["Author"] = lastCommit.Author
ctx.HTML(200, WIKI_VIEW)
}
func WikiList(ctx *middleware.Context) {
}
func NewWiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
@ -51,12 +106,12 @@ func NewWikiPost(ctx *middleware.Context, form auth.NewWikiForm) {
return
}
if err := ctx.Repo.Repository.AddWikiPage(form.Title, form.Content, form.Message); err != nil {
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, form.Title, form.Content, form.Message); err != nil {
ctx.Handle(500, "AddWikiPage", err)
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageName(form.Title))
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(form.Title))
}
func EditWiki(ctx *middleware.Context) {

View file

@ -12,7 +12,7 @@
<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>
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea required>
</div>
<div class="field">
<input name="message" placeholder="{{.i18n.Tr "repo.wiki.default_commit_message"}}">

View file

@ -0,0 +1,18 @@
{{template "base/head" .}}
<div class="repository wiki view">
{{template "repo/header" .}}
<div class="ui container">
{{template "repo/sidebar" .}}
<div class="ui dividing header">
{{.Title}}
<div class="ui sub header">
{{$timeSince := TimeSince .Author.When $.Lang}}
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
</div>
</div>
<div class="ui segment markdown">
{{.Content | Str2html}}
</div>
</div>
</div>
{{template "base/footer" .}}