2020-01-12 15:11:17 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repository
import (
"fmt"
"strings"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
2020-06-07 03:45:12 +03:00
"code.gitea.io/gitea/modules/structs"
2020-01-12 15:11:17 +03:00
)
// ForkRepository forks a repository
func ForkRepository ( doer , owner * models . User , oldRepo * models . Repository , name , desc string ) ( _ * models . Repository , err error ) {
forkedRepo , err := oldRepo . GetUserFork ( owner . ID )
if err != nil {
return nil , err
}
if forkedRepo != nil {
return nil , models . ErrForkAlreadyExist {
Uname : owner . Name ,
RepoName : oldRepo . FullName ( ) ,
ForkName : forkedRepo . FullName ( ) ,
}
}
repo := & models . Repository {
OwnerID : owner . ID ,
Owner : owner ,
OwnerName : owner . Name ,
Name : name ,
LowerName : strings . ToLower ( name ) ,
Description : desc ,
DefaultBranch : oldRepo . DefaultBranch ,
2020-06-07 03:45:12 +03:00
IsPrivate : oldRepo . IsPrivate || oldRepo . Owner . Visibility == structs . VisibleTypePrivate ,
2020-01-12 15:11:17 +03:00
IsEmpty : oldRepo . IsEmpty ,
IsFork : true ,
ForkID : oldRepo . ID ,
}
oldRepoPath := oldRepo . RepoPath ( )
err = models . WithTx ( func ( ctx models . DBContext ) error {
if err = models . CreateRepository ( ctx , doer , owner , repo ) ; err != nil {
return err
}
if err = models . IncrementRepoForkNum ( ctx , oldRepo . ID ) ; err != nil {
return err
}
repoPath := models . RepoPath ( owner . Name , repo . Name )
if stdout , err := git . NewCommand (
"clone" , "--bare" , oldRepoPath , repoPath ) .
SetDescription ( fmt . Sprintf ( "ForkRepository(git clone): %s to %s" , oldRepo . FullName ( ) , repo . FullName ( ) ) ) .
RunInDirTimeout ( 10 * time . Minute , "" ) ; err != nil {
log . Error ( "Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v" , repo , oldRepo , stdout , err )
return fmt . Errorf ( "git clone: %v" , err )
}
if stdout , err := git . NewCommand ( "update-server-info" ) .
SetDescription ( fmt . Sprintf ( "ForkRepository(git update-server-info): %s" , repo . FullName ( ) ) ) .
RunInDir ( repoPath ) ; err != nil {
log . Error ( "Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v" , repo , stdout , err )
return fmt . Errorf ( "git update-server-info: %v" , err )
}
2020-01-20 23:01:19 +03:00
if err = createDelegateHooks ( repoPath ) ; err != nil {
2020-01-12 15:11:17 +03:00
return fmt . Errorf ( "createDelegateHooks: %v" , err )
}
return nil
} )
if err != nil {
return nil , err
}
ctx := models . DefaultDBContext ( )
if err = repo . UpdateSize ( ctx ) ; err != nil {
log . Error ( "Failed to update size for repository: %v" , err )
}
2020-04-08 15:13:04 +03:00
if err := models . CopyLanguageStat ( oldRepo , repo ) ; err != nil {
log . Error ( "Copy language stat from oldRepo failed" )
}
2020-01-12 15:11:17 +03:00
return repo , models . CopyLFS ( ctx , repo , oldRepo )
}