Skip to content

Move wiki related funtions from models to services/wiki #9355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
313 changes: 0 additions & 313 deletions models/wiki.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,12 @@
package models

import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/sync"

"github.com/unknwon/com"
)

var (
reservedUncycloNames = []string{"_pages", "_new", "_edit", "raw"}
wikiWorkingPool = sync.NewExclusivePool()
)

// NormalizeUncycloName normalizes a wiki name
func NormalizeUncycloName(name string) string {
return strings.Replace(name, "-", " ", -1)
}

// UncycloNameToSubURL converts a wiki name to its corresponding sub-URL.
func UncycloNameToSubURL(name string) string {
return url.QueryEscape(strings.Replace(name, " ", "-", -1))
}

// UncycloNameToFilename converts a wiki name to its corresponding filename.
func UncycloNameToFilename(name string) string {
name = strings.Replace(name, " ", "-", -1)
return url.QueryEscape(name) + ".md"
}

// UncycloFilenameToName converts a wiki filename to its corresponding page name.
func UncycloFilenameToName(filename string) (string, error) {
if !strings.HasSuffix(filename, ".md") {
return "", ErrUncycloInvalidFileName{filename}
}
basename := filename[:len(filename)-3]
unescaped, err := url.QueryUnescape(basename)
if err != nil {
return "", err
}
return NormalizeUncycloName(unescaped), nil
}

// UncycloCloneLink returns clone URLs of repository wiki.
func (repo *Repository) UncycloCloneLink() *CloneLink {
return repo.cloneLink(x, true)
Expand All @@ -71,275 +30,3 @@ func (repo *Repository) UncycloPath() string {
func (repo *Repository) HasUncyclo() bool {
return com.IsDir(repo.UncycloPath())
}

// InitUncyclo initializes a wiki for repository,
// it does nothing when repository already has wiki.
func (repo *Repository) InitUncyclo() error {
if repo.HasUncyclo() {
return nil
}

if err := git.InitRepository(repo.UncycloPath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
} else if err = createDelegateHooks(repo.UncycloPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %v", err)
}
return nil
}

// nameAllowed checks if a wiki name is allowed
func nameAllowed(name string) error {
for _, reservedName := range reservedUncycloNames {
if name == reservedName {
return ErrUncycloReservedName{name}
}
}
return nil
}

// updateUncycloPage adds a new page to the repository wiki.
func (repo *Repository) updateUncycloPage(doer *User, oldUncycloName, newUncycloName, content, message string, isNew bool) (err error) {
if err = nameAllowed(newUncycloName); err != nil {
return err
}
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))

if err = repo.InitUncyclo(); err != nil {
return fmt.Errorf("InitUncyclo: %v", err)
}

hasMasterBranch := git.IsBranchExist(repo.UncycloPath(), "master")

basePath, err := CreateTemporaryPath("update-wiki")
if err != nil {
return err
}
defer func() {
if err := RemoveTemporaryPath(basePath); err != nil {
log.Error("Merge: RemoveTemporaryPath: %s", err)
}
}()

cloneOpts := git.CloneRepoOptions{
Bare: true,
Shared: true,
}

if hasMasterBranch {
cloneOpts.Branch = "master"
}

if err := git.Clone(repo.UncycloPath(), basePath, cloneOpts); err != nil {
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
}

gitRepo, err := git.OpenRepository(basePath)
if err != nil {
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
}
defer gitRepo.Close()

if hasMasterBranch {
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
}
}

newUncycloPath := UncycloNameToFilename(newUncycloName)
if isNew {
filesInIndex, err := gitRepo.LsFiles(newUncycloPath)
if err != nil {
log.Error("%v", err)
return err
}
for _, file := range filesInIndex {
if file == newUncycloPath {
return ErrUncycloAlreadyExist{newUncycloPath}
}
}
} else {
oldUncycloPath := UncycloNameToFilename(oldUncycloName)
filesInIndex, err := gitRepo.LsFiles(oldUncycloPath)
if err != nil {
log.Error("%v", err)
return err
}
found := false
for _, file := range filesInIndex {
if file == oldUncycloPath {
found = true
break
}
}
if found {
err := gitRepo.RemoveFilesFromIndex(oldUncycloPath)
if err != nil {
log.Error("%v", err)
return err
}
}
}

// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here

objectHash, err := gitRepo.HashObject(strings.NewReader(content))
if err != nil {
log.Error("%v", err)
return err
}

if err := gitRepo.AddObjectToIndex("100644", objectHash, newUncycloPath); err != nil {
log.Error("%v", err)
return err
}

tree, err := gitRepo.WriteTree()
if err != nil {
log.Error("%v", err)
return err
}

commitTreeOpts := git.CommitTreeOpts{
Message: message,
}

sign, signingKey := repo.SignUncycloCommit(doer)
if sign {
commitTreeOpts.KeyID = signingKey
} else {
commitTreeOpts.NoGPGSign = true
}
if hasMasterBranch {
commitTreeOpts.Parents = []string{"HEAD"}
}
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, commitTreeOpts)
if err != nil {
log.Error("%v", err)
return err
}

if err := git.Push(basePath, git.PushOptions{
Remote: "origin",
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
Env: FullPushingEnvironment(
doer,
doer,
repo,
repo.Name+".wiki",
0,
),
}); err != nil {
log.Error("%v", err)
return fmt.Errorf("Push: %v", err)
}

return nil
}

// AddUncycloPage adds a new wiki page with a given wikiPath.
func (repo *Repository) AddUncycloPage(doer *User, wikiName, content, message string) error {
return repo.updateUncycloPage(doer, "", wikiName, content, message, true)
}

// EditUncycloPage updates a wiki page identified by its wikiPath,
// optionally also changing wikiPath.
func (repo *Repository) EditUncycloPage(doer *User, oldUncycloName, newUncycloName, content, message string) error {
return repo.updateUncycloPage(doer, oldUncycloName, newUncycloName, content, message, false)
}

// DeleteUncycloPage deletes a wiki page identified by its path.
func (repo *Repository) DeleteUncycloPage(doer *User, wikiName string) (err error) {
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))

if err = repo.InitUncyclo(); err != nil {
return fmt.Errorf("InitUncyclo: %v", err)
}

basePath, err := CreateTemporaryPath("update-wiki")
if err != nil {
return err
}
defer func() {
if err := RemoveTemporaryPath(basePath); err != nil {
log.Error("Merge: RemoveTemporaryPath: %s", err)
}
}()

if err := git.Clone(repo.UncycloPath(), basePath, git.CloneRepoOptions{
Bare: true,
Shared: true,
Branch: "master",
}); err != nil {
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
}

gitRepo, err := git.OpenRepository(basePath)
if err != nil {
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
}
defer gitRepo.Close()

if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
}

wikiPath := UncycloNameToFilename(wikiName)
filesInIndex, err := gitRepo.LsFiles(wikiPath)
found := false
for _, file := range filesInIndex {
if file == wikiPath {
found = true
break
}
}
if found {
err := gitRepo.RemoveFilesFromIndex(wikiPath)
if err != nil {
return err
}
} else {
return os.ErrNotExist
}

// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here

tree, err := gitRepo.WriteTree()
if err != nil {
return err
}
message := "Delete page '" + wikiName + "'"
commitTreeOpts := git.CommitTreeOpts{
Message: message,
Parents: []string{"HEAD"},
}

sign, signingKey := repo.SignUncycloCommit(doer)
if sign {
commitTreeOpts.KeyID = signingKey
} else {
commitTreeOpts.NoGPGSign = true
}

commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, commitTreeOpts)
if err != nil {
return err
}

if err := git.Push(basePath, git.PushOptions{
Remote: "origin",
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
Env: PushingEnvironment(doer, repo),
}); err != nil {
return fmt.Errorf("Push: %v", err)
}

return nil
}
Loading