@@ -78,6 +78,7 @@ type Repository struct {
7878 NumClosedIssues int
7979 NumOpenIssues int `xorm:"-"`
8080 IsPrivate bool
81+ IsMirror bool
8182 IsBare bool
8283 IsGoget bool
8384 DefaultBranch string
@@ -119,13 +120,92 @@ func IsLegalName(repoName string) bool {
119120 return true
120121}
121122
123+ // Mirror represents a mirror information of repository.
124+ type Mirror struct {
125+ Id int64
126+ RepoId int64
127+ RepoName string // <user name>/<repo name>
128+ Interval int // Hour.
129+ Updated time.Time `xorm:"UPDATED"`
130+ NextUpdate time.Time
131+ }
132+
133+ // MirrorRepository creates a mirror repository from source.
134+ func MirrorRepository (repoId int64 , userName , repoName , repoPath , url string ) error {
135+ _ , stderr , err := com .ExecCmd ("git" , "clone" , "--mirror" , url , repoPath )
136+ if err != nil {
137+ return err
138+ } else if strings .Contains (stderr , "fatal:" ) {
139+ return errors .New (stderr )
140+ }
141+
142+ if _ , err = orm .InsertOne (& Mirror {
143+ RepoId : repoId ,
144+ RepoName : strings .ToLower (userName + "/" + repoName ),
145+ Interval : 24 ,
146+ NextUpdate : time .Now ().Add (24 * time .Hour ),
147+ }); err != nil {
148+ return err
149+ }
150+
151+ return git .UnpackRefs (repoPath )
152+ }
153+
154+ // MigrateRepository migrates a existing repository from other project hosting.
155+ func MigrateRepository (user * User , name , desc string , private , mirror bool , url string ) (* Repository , error ) {
156+ repo , err := CreateRepository (user , name , desc , "" , "" , private , mirror , false )
157+ if err != nil {
158+ return nil , err
159+ }
160+
161+ // Clone to temprory path and do the init commit.
162+ tmpDir := filepath .Join (os .TempDir (), fmt .Sprintf ("%d" , time .Now ().Nanosecond ()))
163+ os .MkdirAll (tmpDir , os .ModePerm )
164+
165+ repoPath := RepoPath (user .Name , name )
166+
167+ repo .IsBare = false
168+ if mirror {
169+ if err = MirrorRepository (repo .Id , user .Name , repo .Name , repoPath , url ); err != nil {
170+ return repo , err
171+ }
172+ repo .IsMirror = true
173+ return repo , UpdateRepository (repo )
174+ }
175+
176+ // Clone from local repository.
177+ _ , stderr , err := com .ExecCmd ("git" , "clone" , repoPath , tmpDir )
178+ if err != nil {
179+ return repo , err
180+ } else if strings .Contains (stderr , "fatal:" ) {
181+ return repo , errors .New ("git clone: " + stderr )
182+ }
183+
184+ // Pull data from source.
185+ _ , stderr , err = com .ExecCmdDir (tmpDir , "git" , "pull" , url )
186+ if err != nil {
187+ return repo , err
188+ } else if strings .Contains (stderr , "fatal:" ) {
189+ return repo , errors .New ("git pull: " + stderr )
190+ }
191+
192+ // Push data to local repository.
193+ if _ , stderr , err = com .ExecCmdDir (tmpDir , "git" , "push" , "origin" , "master" ); err != nil {
194+ return repo , err
195+ } else if strings .Contains (stderr , "fatal:" ) {
196+ return repo , errors .New ("git push: " + stderr )
197+ }
198+
199+ return repo , UpdateRepository (repo )
200+ }
201+
122202// CreateRepository creates a repository for given user or orgnaziation.
123- func CreateRepository (user * User , repoName , desc , repoLang , license string , private bool , initReadme bool ) (* Repository , error ) {
124- if ! IsLegalName (repoName ) {
203+ func CreateRepository (user * User , name , desc , lang , license string , private , mirror , initReadme bool ) (* Repository , error ) {
204+ if ! IsLegalName (name ) {
125205 return nil , ErrRepoNameIllegal
126206 }
127207
128- isExist , err := IsRepositoryExist (user , repoName )
208+ isExist , err := IsRepositoryExist (user , name )
129209 if err != nil {
130210 return nil , err
131211 } else if isExist {
@@ -134,13 +214,13 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
134214
135215 repo := & Repository {
136216 OwnerId : user .Id ,
137- Name : repoName ,
138- LowerName : strings .ToLower (repoName ),
217+ Name : name ,
218+ LowerName : strings .ToLower (name ),
139219 Description : desc ,
140220 IsPrivate : private ,
141- IsBare : repoLang == "" && license == "" && ! initReadme ,
221+ IsBare : lang == "" && license == "" && ! initReadme ,
142222 }
143- repoPath := RepoPath (user .Name , repoName )
223+ repoPath := RepoPath (user .Name , repo . Name )
144224
145225 sess := orm .NewSession ()
146226 defer sess .Close ()
@@ -150,23 +230,27 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
150230 if err2 := os .RemoveAll (repoPath ); err2 != nil {
151231 log .Error ("repo.CreateRepository(repo): %v" , err )
152232 return nil , errors .New (fmt .Sprintf (
153- "delete repo directory %s/%s failed(1): %v" , user .Name , repoName , err2 ))
233+ "delete repo directory %s/%s failed(1): %v" , user .Name , repo . Name , err2 ))
154234 }
155235 sess .Rollback ()
156236 return nil , err
157237 }
158238
239+ mode := AU_WRITABLE
240+ if mirror {
241+ mode = AU_READABLE
242+ }
159243 access := Access {
160244 UserName : user .LowerName ,
161245 RepoName : strings .ToLower (path .Join (user .Name , repo .Name )),
162- Mode : AU_WRITABLE ,
246+ Mode : mode ,
163247 }
164248 if _ , err = sess .Insert (& access ); err != nil {
165249 sess .Rollback ()
166250 if err2 := os .RemoveAll (repoPath ); err2 != nil {
167251 log .Error ("repo.CreateRepository(access): %v" , err )
168252 return nil , errors .New (fmt .Sprintf (
169- "delete repo directory %s/%s failed(2): %v" , user .Name , repoName , err2 ))
253+ "delete repo directory %s/%s failed(2): %v" , user .Name , repo . Name , err2 ))
170254 }
171255 return nil , err
172256 }
@@ -177,7 +261,7 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
177261 if err2 := os .RemoveAll (repoPath ); err2 != nil {
178262 log .Error ("repo.CreateRepository(repo count): %v" , err )
179263 return nil , errors .New (fmt .Sprintf (
180- "delete repo directory %s/%s failed(3): %v" , user .Name , repoName , err2 ))
264+ "delete repo directory %s/%s failed(3): %v" , user .Name , repo . Name , err2 ))
181265 }
182266 return nil , err
183267 }
@@ -187,7 +271,7 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
187271 if err2 := os .RemoveAll (repoPath ); err2 != nil {
188272 log .Error ("repo.CreateRepository(commit): %v" , err )
189273 return nil , errors .New (fmt .Sprintf (
190- "delete repo directory %s/%s failed(3): %v" , user .Name , repoName , err2 ))
274+ "delete repo directory %s/%s failed(3): %v" , user .Name , repo . Name , err2 ))
191275 }
192276 return nil , err
193277 }
@@ -202,7 +286,12 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
202286 log .Error ("repo.CreateRepository(WatchRepo): %v" , err )
203287 }
204288
205- if err = initRepository (repoPath , user , repo , initReadme , repoLang , license ); err != nil {
289+ // No need for init for mirror.
290+ if mirror {
291+ return repo , nil
292+ }
293+
294+ if err = initRepository (repoPath , user , repo , initReadme , lang , license ); err != nil {
206295 return nil , err
207296 }
208297
@@ -304,9 +393,13 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
304393 tmpDir := filepath .Join (os .TempDir (), fmt .Sprintf ("%d" , time .Now ().Nanosecond ()))
305394 os .MkdirAll (tmpDir , os .ModePerm )
306395
307- if _ , _ , err := com .ExecCmd ("git" , "clone" , repoPath , tmpDir ); err != nil {
396+ _ , stderr , err := com .ExecCmd ("git" , "clone" , repoPath , tmpDir )
397+ if err != nil {
308398 return err
309399 }
400+ if len (stderr ) > 0 {
401+ log .Trace ("repo.initRepository(git clone): %s" , stderr )
402+ }
310403
311404 // README
312405 if initReadme {
@@ -379,6 +472,7 @@ func GetRepos(num, offset int) ([]UserRepo, error) {
379472 return urepos , nil
380473}
381474
475+ // RepoPath returns repository path by given user and repository name.
382476func RepoPath (userName , repoName string ) string {
383477 return filepath .Join (UserPath (userName ), strings .ToLower (repoName )+ ".git" )
384478}
@@ -519,15 +613,20 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
519613 sess .Rollback ()
520614 return err
521615 }
522- rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?"
523- if _ , err = sess .Exec (rawSql , userId ); err != nil {
616+ if _ , err := sess .Delete (& Action {RepoId : repo .Id }); err != nil {
524617 sess .Rollback ()
525618 return err
526619 }
527620 if _ , err = sess .Delete (& Watch {RepoId : repoId }); err != nil {
528621 sess .Rollback ()
529622 return err
530623 }
624+
625+ rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?"
626+ if _ , err = sess .Exec (rawSql , userId ); err != nil {
627+ sess .Rollback ()
628+ return err
629+ }
531630 if err = sess .Commit (); err != nil {
532631 sess .Rollback ()
533632 return err
0 commit comments