@@ -6,14 +6,14 @@ package models
6
6
7
7
import (
8
8
"fmt"
9
- "io/ioutil"
10
9
"net/url"
11
10
"os"
12
11
"path"
13
12
"path/filepath"
14
13
"strings"
15
14
16
15
"code.gitea.io/gitea/modules/git"
16
+ "code.gitea.io/gitea/modules/log"
17
17
"code.gitea.io/gitea/modules/setting"
18
18
"code.gitea.io/gitea/modules/sync"
19
19
@@ -102,21 +102,6 @@ func (repo *Repository) LocalUncycloPath() string {
102
102
return path .Join (LocalUncycloPath (), com .ToStr (repo .ID ))
103
103
}
104
104
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
-
120
105
// nameAllowed checks if a wiki name is allowed
121
106
func nameAllowed (name string ) error {
122
107
for _ , reservedName := range reservedUncycloNames {
@@ -132,66 +117,120 @@ func (repo *Repository) updateUncycloPage(doer *User, oldUncycloName, newUncycloName, con
132
117
if err = nameAllowed (newUncycloName ); err != nil {
133
118
return err
134
119
}
135
-
136
120
wikiWorkingPool .CheckIn (com .ToStr (repo .ID ))
137
121
defer wikiWorkingPool .CheckOut (com .ToStr (repo .ID ))
138
122
139
123
if err = repo .InitUncyclo (); err != nil {
140
124
return fmt .Errorf ("InitUncyclo: %v" , err )
141
125
}
142
126
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" )
149
128
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
+ }
151
134
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"
156
137
}
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 )
161
142
}
162
- }
163
143
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
+ }
172
149
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
+ }
176
156
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
+ }
193
191
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
+ })
195
234
}
196
235
197
236
// AddUncycloPage adds a new wiki page with a given wikiPath.
@@ -210,34 +249,73 @@ func (repo *Repository) DeleteUncycloPage(doer *User, wikiName string) (err error)
210
249
wikiWorkingPool .CheckIn (com .ToStr (repo .ID ))
211
250
defer wikiWorkingPool .CheckOut (com .ToStr (repo .ID ))
212
251
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 )
218
254
}
219
255
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
+ }
221
265
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
+ }
225
271
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
+ }
241
276
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
+ })
243
321
}
0 commit comments