Skip to content

Commit 2ffa506

Browse files
committed
Remove Uncyclo LocalCopy Checkouts
1 parent 042755b commit 2ffa506

File tree

7 files changed

+362
-111
lines changed

7 files changed

+362
-111
lines changed

models/helper_directory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func LocalCopyPath() string {
2727
// CreateTemporaryPath creates a temporary path
2828
func CreateTemporaryPath(prefix string) (string, error) {
2929
timeStr := com.ToStr(time.Now().Nanosecond()) // SHOULD USE SOMETHING UNIQUE
30-
basePath := filepath.Join(LocalCopyPath(), prefix+"-"+timeStr+".git")
30+
basePath := path.Join(LocalCopyPath(), prefix+"-"+timeStr+".git")
3131
if err := os.MkdirAll(filepath.Dir(basePath), os.ModePerm); err != nil {
3232
log.Error("Unable to create temporary directory: %s (%v)", basePath, err)
3333
return "", fmt.Errorf("Failed to create dir %s: %v", basePath, err)

models/repo_branch.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,6 @@ import (
1515
"github.com/Unknwon/com"
1616
)
1717

18-
// discardLocalRepoBranchChanges discards local commits/changes of
19-
// given branch to make sure it is even to remote branch.
20-
func discardLocalRepoBranchChanges(localPath, branch string) error {
21-
if !com.IsExist(localPath) {
22-
return nil
23-
}
24-
// No need to check if nothing in the repository.
25-
if !git.IsBranchExist(localPath, branch) {
26-
return nil
27-
}
28-
29-
refName := "origin/" + branch
30-
if err := git.ResetHEAD(localPath, true, refName); err != nil {
31-
return fmt.Errorf("git reset --hard %s: %v", refName, err)
32-
}
33-
return nil
34-
}
35-
36-
// DiscardLocalRepoBranchChanges discards the local repository branch changes
37-
func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
38-
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
39-
}
40-
4118
// checkoutNewBranch checks out to a new branch from the a branch name.
4219
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
4320
if err := git.Checkout(localPath, git.CheckoutOptions{

models/wiki.go

Lines changed: 164 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ package models
66

77
import (
88
"fmt"
9-
"io/ioutil"
109
"net/url"
1110
"os"
1211
"path"
1312
"path/filepath"
1413
"strings"
1514

1615
"code.gitea.io/gitea/modules/git"
16+
"code.gitea.io/gitea/modules/log"
1717
"code.gitea.io/gitea/modules/setting"
1818
"code.gitea.io/gitea/modules/sync"
1919

@@ -102,21 +102,6 @@ func (repo *Repository) LocalUncycloPath() string {
102102
return path.Join(LocalUncycloPath(), com.ToStr(repo.ID))
103103
}
104104

105-
// UpdateLocalUncyclo makes sure the local copy of repository wiki is up-to-date.
106-
func (repo *Repository) updateLocalUncyclo() error {
107-
// Don't pass branch name here because it fails to clone and
108-
// checkout to a specific branch when wiki is an empty repository.
109-
var branch = ""
110-
if com.IsExist(repo.LocalUncycloPath()) {
111-
branch = "master"
112-
}
113-
return UpdateLocalCopyBranch(repo.UncycloPath(), repo.LocalUncycloPath(), branch)
114-
}
115-
116-
func discardLocalUncycloChanges(localPath string) error {
117-
return discardLocalRepoBranchChanges(localPath, "master")
118-
}
119-
120105
// nameAllowed checks if a wiki name is allowed
121106
func nameAllowed(name string) error {
122107
for _, reservedName := range reservedUncycloNames {
@@ -132,66 +117,120 @@ func (repo *Repository) updateUncycloPage(doer *User, oldUncycloName, newUncycloName, con
132117
if err = nameAllowed(newUncycloName); err != nil {
133118
return err
134119
}
135-
136120
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
137121
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
138122

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

143-
localPath := repo.LocalUncycloPath()
144-
if err = discardLocalUncycloChanges(localPath); err != nil {
145-
return fmt.Errorf("discardLocalUncycloChanges: %v", err)
146-
} else if err = repo.updateLocalUncyclo(); err != nil {
147-
return fmt.Errorf("UpdateLocalUncyclo: %v", err)
148-
}
127+
hasMasterBranch := git.IsBranchExist(repo.UncycloPath(), "master")
149128

150-
newUncycloPath := path.Join(localPath, UncycloNameToFilename(newUncycloName))
129+
return WithTemporaryPath("update-wiki", func(basePath string) error {
130+
cloneOpts := git.CloneRepoOptions{
131+
Bare: true,
132+
Shared: true,
133+
}
151134

152-
// If not a new file, show perform update not create.
153-
if isNew {
154-
if com.IsExist(newUncycloPath) {
155-
return ErrUncycloAlreadyExist{newUncycloPath}
135+
if hasMasterBranch {
136+
cloneOpts.Branch = "master"
156137
}
157-
} else {
158-
oldUncycloPath := path.Join(localPath, UncycloNameToFilename(oldUncycloName))
159-
if err := os.Remove(oldUncycloPath); err != nil {
160-
return fmt.Errorf("Failed to remove %s: %v", oldUncycloPath, err)
138+
139+
if err := git.Clone(repo.UncycloPath(), basePath, cloneOpts); err != nil {
140+
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
141+
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
161142
}
162-
}
163143

164-
// SECURITY: if new file is a symlink to non-exist critical file,
165-
// attack content can be written to the target file (e.g. authorized_keys2)
166-
// as a new page operation.
167-
// So we want to make sure the symlink is removed before write anything.
168-
// The new file we created will be in normal text format.
169-
if err = os.RemoveAll(newUncycloPath); err != nil {
170-
return err
171-
}
144+
gitRepo, err := git.OpenRepository(basePath)
145+
if err != nil {
146+
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
147+
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
148+
}
172149

173-
if err = ioutil.WriteFile(newUncycloPath, []byte(content), 0666); err != nil {
174-
return fmt.Errorf("WriteFile: %v", err)
175-
}
150+
if hasMasterBranch {
151+
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
152+
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
153+
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
154+
}
155+
}
176156

177-
if len(message) == 0 {
178-
message = "Update page '" + newUncycloName + "'"
179-
}
180-
if err = git.AddChanges(localPath, true); err != nil {
181-
return fmt.Errorf("AddChanges: %v", err)
182-
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
183-
Committer: doer.NewGitSig(),
184-
Message: message,
185-
}); err != nil {
186-
return fmt.Errorf("CommitChanges: %v", err)
187-
} else if err = git.Push(localPath, git.PushOptions{
188-
Remote: "origin",
189-
Branch: "master",
190-
}); err != nil {
191-
return fmt.Errorf("Push: %v", err)
192-
}
157+
newUncycloPath := UncycloNameToFilename(newUncycloName)
158+
if isNew {
159+
filesInIndex, err := gitRepo.LsFiles(newUncycloPath)
160+
if err != nil {
161+
log.Error("%v", err)
162+
return err
163+
}
164+
for _, file := range filesInIndex {
165+
if file == newUncycloPath {
166+
return ErrUncycloAlreadyExist{newUncycloPath}
167+
}
168+
}
169+
} else {
170+
oldUncycloPath := UncycloNameToFilename(oldUncycloName)
171+
filesInIndex, err := gitRepo.LsFiles(oldUncycloPath)
172+
if err != nil {
173+
log.Error("%v", err)
174+
return err
175+
}
176+
found := false
177+
for _, file := range filesInIndex {
178+
if file == oldUncycloPath {
179+
found = true
180+
break
181+
}
182+
}
183+
if found {
184+
err := gitRepo.RemoveFilesFromIndex(oldUncycloPath)
185+
if err != nil {
186+
log.Error("%v", err)
187+
return err
188+
}
189+
}
190+
}
193191

194-
return nil
192+
// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
193+
194+
objectHash, err := gitRepo.HashObject(strings.NewReader(content))
195+
if err != nil {
196+
log.Error("%v", err)
197+
return err
198+
}
199+
200+
if err := gitRepo.AddObjectToIndex("100644", objectHash, newUncycloPath); err != nil {
201+
log.Error("%v", err)
202+
return err
203+
}
204+
205+
tree, err := gitRepo.WriteTree()
206+
if err != nil {
207+
log.Error("%v", err)
208+
return err
209+
}
210+
211+
commitTreeOpts := git.CommitTreeOpts{
212+
Message: message,
213+
}
214+
if hasMasterBranch {
215+
commitTreeOpts.Parents = []string{"HEAD"}
216+
}
217+
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, commitTreeOpts)
218+
if err != nil {
219+
log.Error("%v", err)
220+
return err
221+
}
222+
223+
if err := git.Push(basePath, git.PushOptions{
224+
Remote: "origin",
225+
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
226+
Env: PushingEnvironment(doer, repo),
227+
}); err != nil {
228+
log.Error("%v", err)
229+
return fmt.Errorf("Push: %v", err)
230+
}
231+
232+
return nil
233+
})
195234
}
196235

197236
// AddUncycloPage adds a new wiki page with a given wikiPath.
@@ -210,34 +249,73 @@ func (repo *Repository) DeleteUncycloPage(doer *User, wikiName string) (err error)
210249
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
211250
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
212251

213-
localPath := repo.LocalUncycloPath()
214-
if err = discardLocalUncycloChanges(localPath); err != nil {
215-
return fmt.Errorf("discardLocalUncycloChanges: %v", err)
216-
} else if err = repo.updateLocalUncyclo(); err != nil {
217-
return fmt.Errorf("UpdateLocalUncyclo: %v", err)
252+
if err = repo.InitUncyclo(); err != nil {
253+
return fmt.Errorf("InitUncyclo: %v", err)
218254
}
219255

220-
filename := path.Join(localPath, UncycloNameToFilename(wikiName))
256+
return WithTemporaryPath("update-wiki", func(basePath string) error {
257+
if err := git.Clone(repo.UncycloPath(), basePath, git.CloneRepoOptions{
258+
Bare: true,
259+
Shared: true,
260+
Branch: "master",
261+
}); err != nil {
262+
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
263+
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
264+
}
221265

222-
if err := os.Remove(filename); err != nil {
223-
return fmt.Errorf("Failed to remove %s: %v", filename, err)
224-
}
266+
gitRepo, err := git.OpenRepository(basePath)
267+
if err != nil {
268+
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
269+
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
270+
}
225271

226-
message := "Delete page '" + wikiName + "'"
227-
228-
if err = git.AddChanges(localPath, true); err != nil {
229-
return fmt.Errorf("AddChanges: %v", err)
230-
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
231-
Committer: doer.NewGitSig(),
232-
Message: message,
233-
}); err != nil {
234-
return fmt.Errorf("CommitChanges: %v", err)
235-
} else if err = git.Push(localPath, git.PushOptions{
236-
Remote: "origin",
237-
Branch: "master",
238-
}); err != nil {
239-
return fmt.Errorf("Push: %v", err)
240-
}
272+
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
273+
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
274+
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
275+
}
241276

242-
return nil
277+
wikiPath := UncycloNameToFilename(wikiName)
278+
filesInIndex, err := gitRepo.LsFiles(wikiPath)
279+
found := false
280+
for _, file := range filesInIndex {
281+
if file == wikiPath {
282+
found = true
283+
break
284+
}
285+
}
286+
if found {
287+
err := gitRepo.RemoveFilesFromIndex(wikiPath)
288+
if err != nil {
289+
return err
290+
}
291+
} else {
292+
return os.ErrNotExist
293+
}
294+
295+
// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
296+
297+
tree, err := gitRepo.WriteTree()
298+
if err != nil {
299+
return err
300+
}
301+
message := "Delete page '" + wikiName + "'"
302+
303+
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, git.CommitTreeOpts{
304+
Message: message,
305+
Parents: []string{"HEAD"},
306+
})
307+
if err != nil {
308+
return err
309+
}
310+
311+
if err := git.Push(basePath, git.PushOptions{
312+
Remote: "origin",
313+
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
314+
Env: PushingEnvironment(doer, repo),
315+
}); err != nil {
316+
return fmt.Errorf("Push: %v", err)
317+
}
318+
319+
return nil
320+
})
243321
}

modules/git/command.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ func (c *Command) AddArguments(args ...string) *Command {
5555
// RunInDirTimeoutEnvPipeline executes the command in given directory with given timeout,
5656
// it pipes stdout and stderr to given io.Writer.
5757
func (c *Command) RunInDirTimeoutEnvPipeline(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer) error {
58+
return c.RunInDirTimeoutEnvFullPipeline(env, timeout, dir, stdout, stderr, nil)
59+
}
60+
61+
// RunInDirTimeoutEnvFullPipeline executes the command in given directory with given timeout,
62+
// it pipes stdout and stderr to given io.Writer and passes in an io.Reader as stdin.
63+
func (c *Command) RunInDirTimeoutEnvFullPipeline(env []string, timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader) error {
5864
if timeout == -1 {
5965
timeout = DefaultCommandExecutionTimeout
6066
}
@@ -73,6 +79,7 @@ func (c *Command) RunInDirTimeoutEnvPipeline(env []string, timeout time.Duration
7379
cmd.Dir = dir
7480
cmd.Stdout = stdout
7581
cmd.Stderr = stderr
82+
cmd.Stdin = stdin
7683
if err := cmd.Start(); err != nil {
7784
return err
7885
}
@@ -90,6 +97,12 @@ func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, std
9097
return c.RunInDirTimeoutEnvPipeline(nil, timeout, dir, stdout, stderr)
9198
}
9299

100+
// RunInDirTimeoutFullPipeline executes the command in given directory with given timeout,
101+
// it pipes stdout and stderr to given io.Writer, and stdin from the given io.Reader
102+
func (c *Command) RunInDirTimeoutFullPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer, stdin io.Reader) error {
103+
return c.RunInDirTimeoutEnvFullPipeline(nil, timeout, dir, stdout, stderr, stdin)
104+
}
105+
93106
// RunInDirTimeout executes the command in given directory with given timeout,
94107
// and returns stdout in []byte and error (combined with stderr).
95108
func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) {
@@ -114,7 +127,13 @@ func (c *Command) RunInDirTimeoutEnv(env []string, timeout time.Duration, dir st
114127
// RunInDirPipeline executes the command in given directory,
115128
// it pipes stdout and stderr to given io.Writer.
116129
func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
117-
return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr)
130+
return c.RunInDirFullPipeline(dir, stdout, stderr, nil)
131+
}
132+
133+
// RunInDirFullPipeline executes the command in given directory,
134+
// it pipes stdout and stderr to given io.Writer.
135+
func (c *Command) RunInDirFullPipeline(dir string, stdout, stderr io.Writer, stdin io.Reader) error {
136+
return c.RunInDirTimeoutFullPipeline(-1, dir, stdout, stderr, stdin)
118137
}
119138

120139
// RunInDirBytes executes the command in given directory

0 commit comments

Comments
 (0)