summaryrefslogtreecommitdiffstats
path: root/models/wiki.go
diff options
context:
space:
mode:
Diffstat (limited to 'models/wiki.go')
-rw-r--r--models/wiki.go231
1 files changed, 151 insertions, 80 deletions
diff --git a/models/wiki.go b/models/wiki.go
index 0f5cdc20bd..bcf97c0765 100644
--- a/models/wiki.go
+++ b/models/wiki.go
@@ -6,15 +6,13 @@ package models
import (
"fmt"
- "io/ioutil"
"net/url"
"os"
- "path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/sync"
"github.com/Unknwon/com"
@@ -89,34 +87,6 @@ func (repo *Repository) InitWiki() error {
return nil
}
-// LocalWikiPath returns the local wiki repository copy path.
-func LocalWikiPath() string {
- if filepath.IsAbs(setting.Repository.Local.LocalWikiPath) {
- return setting.Repository.Local.LocalWikiPath
- }
- return path.Join(setting.AppDataPath, setting.Repository.Local.LocalWikiPath)
-}
-
-// LocalWikiPath returns the path to the local wiki repository (?).
-func (repo *Repository) LocalWikiPath() string {
- return path.Join(LocalWikiPath(), com.ToStr(repo.ID))
-}
-
-// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
-func (repo *Repository) updateLocalWiki() error {
- // Don't pass branch name here because it fails to clone and
- // checkout to a specific branch when wiki is an empty repository.
- var branch = ""
- if com.IsExist(repo.LocalWikiPath()) {
- branch = "master"
- }
- return UpdateLocalCopyBranch(repo.WikiPath(), repo.LocalWikiPath(), branch)
-}
-
-func discardLocalWikiChanges(localPath string) error {
- return discardLocalRepoBranchChanges(localPath, "master")
-}
-
// nameAllowed checks if a wiki name is allowed
func nameAllowed(name string) error {
for _, reservedName := range reservedWikiNames {
@@ -132,7 +102,6 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
if err = nameAllowed(newWikiName); err != nil {
return err
}
-
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
@@ -140,54 +109,113 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
return fmt.Errorf("InitWiki: %v", err)
}
- localPath := repo.LocalWikiPath()
- if err = discardLocalWikiChanges(localPath); err != nil {
- return fmt.Errorf("discardLocalWikiChanges: %v", err)
- } else if err = repo.updateLocalWiki(); err != nil {
- return fmt.Errorf("UpdateLocalWiki: %v", err)
+ hasMasterBranch := git.IsBranchExist(repo.WikiPath(), "master")
+
+ basePath, err := CreateTemporaryPath("update-wiki")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(basePath)
- newWikiPath := path.Join(localPath, WikiNameToFilename(newWikiName))
+ cloneOpts := git.CloneRepoOptions{
+ Bare: true,
+ Shared: true,
+ }
+
+ if hasMasterBranch {
+ cloneOpts.Branch = "master"
+ }
- // If not a new file, show perform update not create.
+ if err := git.Clone(repo.WikiPath(), 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)
+ }
+
+ 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)
+ }
+ }
+
+ newWikiPath := WikiNameToFilename(newWikiName)
if isNew {
- if com.IsExist(newWikiPath) {
- return ErrWikiAlreadyExist{newWikiPath}
+ filesInIndex, err := gitRepo.LsFiles(newWikiPath)
+ if err != nil {
+ log.Error("%v", err)
+ return err
+ }
+ for _, file := range filesInIndex {
+ if file == newWikiPath {
+ return ErrWikiAlreadyExist{newWikiPath}
+ }
}
} else {
- oldWikiPath := path.Join(localPath, WikiNameToFilename(oldWikiName))
- if err := os.Remove(oldWikiPath); err != nil {
- return fmt.Errorf("Failed to remove %s: %v", oldWikiPath, err)
+ oldWikiPath := WikiNameToFilename(oldWikiName)
+ filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
+ if err != nil {
+ log.Error("%v", err)
+ return err
+ }
+ found := false
+ for _, file := range filesInIndex {
+ if file == oldWikiPath {
+ found = true
+ break
+ }
+ }
+ if found {
+ err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
+ if err != nil {
+ log.Error("%v", err)
+ return err
+ }
}
}
- // SECURITY: if new file is a symlink to non-exist critical file,
- // attack content can be written to the target file (e.g. authorized_keys2)
- // as a new page operation.
- // So we want to make sure the symlink is removed before write anything.
- // The new file we created will be in normal text format.
- if err = os.RemoveAll(newWikiPath); err != nil {
+ // 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 = ioutil.WriteFile(newWikiPath, []byte(content), 0666); err != nil {
- return fmt.Errorf("WriteFile: %v", err)
+ if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
+ log.Error("%v", err)
+ return err
}
- if len(message) == 0 {
- message = "Update page '" + newWikiName + "'"
+ tree, err := gitRepo.WriteTree()
+ if err != nil {
+ log.Error("%v", err)
+ return err
}
- if err = git.AddChanges(localPath, true); err != nil {
- return fmt.Errorf("AddChanges: %v", err)
- } else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
- Committer: doer.NewGitSig(),
- Message: message,
- }); err != nil {
- return fmt.Errorf("CommitChanges: %v", err)
- } else if err = git.Push(localPath, git.PushOptions{
+
+ commitTreeOpts := git.CommitTreeOpts{
+ Message: message,
+ }
+ 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: "master",
+ Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
+ log.Error("%v", err)
return fmt.Errorf("Push: %v", err)
}
@@ -210,31 +238,74 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error)
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
- localPath := repo.LocalWikiPath()
- if err = discardLocalWikiChanges(localPath); err != nil {
- return fmt.Errorf("discardLocalWikiChanges: %v", err)
- } else if err = repo.updateLocalWiki(); err != nil {
- return fmt.Errorf("UpdateLocalWiki: %v", err)
+ if err = repo.InitWiki(); err != nil {
+ return fmt.Errorf("InitWiki: %v", err)
+ }
+
+ basePath, err := CreateTemporaryPath("update-wiki")
+ if err != nil {
+ return err
}
+ defer RemoveTemporaryPath(basePath)
- filename := path.Join(localPath, WikiNameToFilename(wikiName))
+ if err := git.Clone(repo.WikiPath(), 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)
+ }
- if err := os.Remove(filename); err != nil {
- return fmt.Errorf("Failed to remove %s: %v", filename, 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)
}
+ 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 := WikiNameToFilename(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 + "'"
- if err = git.AddChanges(localPath, true); err != nil {
- return fmt.Errorf("AddChanges: %v", err)
- } else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
- Committer: doer.NewGitSig(),
- Message: message,
- }); err != nil {
- return fmt.Errorf("CommitChanges: %v", err)
- } else if err = git.Push(localPath, git.PushOptions{
+ commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, git.CommitTreeOpts{
+ Message: message,
+ Parents: []string{"HEAD"},
+ })
+ if err != nil {
+ return err
+ }
+
+ if err := git.Push(basePath, git.PushOptions{
Remote: "origin",
- Branch: "master",
+ Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
+ Env: PushingEnvironment(doer, repo),
}); err != nil {
return fmt.Errorf("Push: %v", err)
}