|
|
|
@ -5,6 +5,7 @@ |
|
|
|
|
package models |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"html/template" |
|
|
|
@ -403,7 +404,12 @@ func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) er |
|
|
|
|
|
|
|
|
|
// MigrateRepository migrates a existing repository from other project hosting.
|
|
|
|
|
func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) { |
|
|
|
|
repo, err := CreateRepository(u, name, desc, "", "", private, mirror, false) |
|
|
|
|
repo, err := CreateRepository(u, CreateRepoOptions{ |
|
|
|
|
Name: name, |
|
|
|
|
Description: desc, |
|
|
|
|
IsPrivate: private, |
|
|
|
|
IsMirror: mirror, |
|
|
|
|
}) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
@ -488,93 +494,123 @@ func createUpdateHook(repoPath string) error { |
|
|
|
|
[]byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"", setting.CustomConf)), 0777) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// InitRepository initializes README and .gitignore if needed.
|
|
|
|
|
func initRepository(e Engine, repoPath string, u *User, repo *Repository, initReadme bool, repoLang, license string) error { |
|
|
|
|
// Somehow the directory could exist.
|
|
|
|
|
if com.IsExist(repoPath) { |
|
|
|
|
return fmt.Errorf("initRepository: path already exists: %s", repoPath) |
|
|
|
|
type CreateRepoOptions struct { |
|
|
|
|
Name string |
|
|
|
|
Description string |
|
|
|
|
Gitignores string |
|
|
|
|
License string |
|
|
|
|
Readme string |
|
|
|
|
IsPrivate bool |
|
|
|
|
IsMirror bool |
|
|
|
|
AutoInit bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Init bare new repository.
|
|
|
|
|
os.MkdirAll(repoPath, os.ModePerm) |
|
|
|
|
_, stderr, err := process.ExecDir(-1, repoPath, |
|
|
|
|
fmt.Sprintf("initRepository(git init --bare): %s", repoPath), |
|
|
|
|
"git", "init", "--bare") |
|
|
|
|
func getRepoInitFile(tp, name string) ([]byte, error) { |
|
|
|
|
relPath := path.Join("conf", tp, name) |
|
|
|
|
|
|
|
|
|
// Use custom file when available.
|
|
|
|
|
customPath := path.Join(setting.CustomPath, relPath) |
|
|
|
|
if com.IsFile(customPath) { |
|
|
|
|
return ioutil.ReadFile(customPath) |
|
|
|
|
} |
|
|
|
|
return bindata.Asset(relPath) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { |
|
|
|
|
// Clone to temprory path and do the init commit.
|
|
|
|
|
_, stderr, err := process.Exec( |
|
|
|
|
fmt.Sprintf("initRepository(git clone): %s", repoPath), "git", "clone", repoPath, tmpDir) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("git init --bare: %s", err) |
|
|
|
|
return fmt.Errorf("git clone: %v - %s", err, stderr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := createUpdateHook(repoPath); err != nil { |
|
|
|
|
return err |
|
|
|
|
// README
|
|
|
|
|
data, err := getRepoInitFile("readme", opts.Readme) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("getRepoInitFile[%s]: %v", opts.Readme, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Initialize repository according to user's choice.
|
|
|
|
|
fileName := map[string]string{} |
|
|
|
|
if initReadme { |
|
|
|
|
fileName["readme"] = "README.md" |
|
|
|
|
match := map[string]string{ |
|
|
|
|
"Name": repo.Name, |
|
|
|
|
"Description": repo.Description, |
|
|
|
|
} |
|
|
|
|
if repoLang != "" { |
|
|
|
|
fileName["gitign"] = ".gitignore" |
|
|
|
|
if err = ioutil.WriteFile(filepath.Join(tmpDir, "README.md"), |
|
|
|
|
[]byte(com.Expand(string(data), match)), 0644); err != nil { |
|
|
|
|
return fmt.Errorf("write README.md: %v", err) |
|
|
|
|
} |
|
|
|
|
if license != "" { |
|
|
|
|
fileName["license"] = "LICENSE" |
|
|
|
|
|
|
|
|
|
// .gitignore
|
|
|
|
|
if len(opts.Gitignores) > 0 { |
|
|
|
|
var buf bytes.Buffer |
|
|
|
|
names := strings.Split(opts.Gitignores, ",") |
|
|
|
|
for _, name := range names { |
|
|
|
|
data, err = getRepoInitFile("gitignore", name) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("getRepoInitFile[%s]: %v", name, err) |
|
|
|
|
} |
|
|
|
|
buf.WriteString("# ---> " + name + "\n") |
|
|
|
|
buf.Write(data) |
|
|
|
|
buf.WriteString("\n") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Clone to temprory path and do the init commit.
|
|
|
|
|
tmpDir := filepath.Join(os.TempDir(), com.ToStr(time.Now().Nanosecond())) |
|
|
|
|
os.MkdirAll(tmpDir, os.ModePerm) |
|
|
|
|
defer os.RemoveAll(tmpDir) |
|
|
|
|
if buf.Len() > 0 { |
|
|
|
|
if err = ioutil.WriteFile(filepath.Join(tmpDir, ".gitignore"), buf.Bytes(), 0644); err != nil { |
|
|
|
|
return fmt.Errorf("write .gitignore: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_, stderr, err = process.Exec( |
|
|
|
|
fmt.Sprintf("initRepository(git clone): %s", repoPath), |
|
|
|
|
"git", "clone", repoPath, tmpDir) |
|
|
|
|
// LICENSE
|
|
|
|
|
if len(opts.License) > 0 { |
|
|
|
|
data, err = getRepoInitFile("license", opts.License) |
|
|
|
|
if err != nil { |
|
|
|
|
return errors.New("git clone: " + stderr) |
|
|
|
|
return fmt.Errorf("getRepoInitFile[%s]: %v", opts.License, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// README
|
|
|
|
|
if initReadme { |
|
|
|
|
defaultReadme := repo.Name + "\n" + strings.Repeat("=", |
|
|
|
|
utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description |
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(tmpDir, fileName["readme"]), |
|
|
|
|
[]byte(defaultReadme), 0644); err != nil { |
|
|
|
|
return err |
|
|
|
|
if err = ioutil.WriteFile(filepath.Join(tmpDir, "LICENSE"), data, 0644); err != nil { |
|
|
|
|
return fmt.Errorf("write LICENSE: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FIXME: following two can be merged.
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// .gitignore
|
|
|
|
|
// Copy custom file when available.
|
|
|
|
|
customPath := path.Join(setting.CustomPath, "conf/gitignore", repoLang) |
|
|
|
|
targetPath := path.Join(tmpDir, fileName["gitign"]) |
|
|
|
|
if com.IsFile(customPath) { |
|
|
|
|
if err := com.Copy(customPath, targetPath); err != nil { |
|
|
|
|
return fmt.Errorf("copy gitignore: %v", err) |
|
|
|
|
// InitRepository initializes README and .gitignore if needed.
|
|
|
|
|
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) error { |
|
|
|
|
// Somehow the directory could exist.
|
|
|
|
|
if com.IsExist(repoPath) { |
|
|
|
|
return fmt.Errorf("initRepository: path already exists: %s", repoPath) |
|
|
|
|
} |
|
|
|
|
} else if com.IsSliceContainsStr(Gitignores, repoLang) { |
|
|
|
|
if err = ioutil.WriteFile(targetPath, |
|
|
|
|
bindata.MustAsset(path.Join("conf/gitignore", repoLang)), 0644); err != nil { |
|
|
|
|
return fmt.Errorf("generate gitignore: %v", err) |
|
|
|
|
|
|
|
|
|
// Init bare new repository.
|
|
|
|
|
os.MkdirAll(repoPath, os.ModePerm) |
|
|
|
|
_, stderr, err := process.ExecDir(-1, repoPath, |
|
|
|
|
fmt.Sprintf("initRepository(git init --bare): %s", repoPath), "git", "init", "--bare") |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("git init --bare: %v - %s", err, stderr) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
delete(fileName, "gitign") |
|
|
|
|
|
|
|
|
|
if err := createUpdateHook(repoPath); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// LICENSE
|
|
|
|
|
customPath = path.Join(setting.CustomPath, "conf/license", license) |
|
|
|
|
targetPath = path.Join(tmpDir, fileName["license"]) |
|
|
|
|
if com.IsFile(customPath) { |
|
|
|
|
if err = com.Copy(customPath, targetPath); err != nil { |
|
|
|
|
return fmt.Errorf("copy license: %v", err) |
|
|
|
|
tmpDir := filepath.Join(os.TempDir(), com.ToStr(time.Now().Nanosecond())) |
|
|
|
|
|
|
|
|
|
// Initialize repository according to user's choice.
|
|
|
|
|
if opts.AutoInit { |
|
|
|
|
os.MkdirAll(tmpDir, os.ModePerm) |
|
|
|
|
defer os.RemoveAll(tmpDir) |
|
|
|
|
|
|
|
|
|
if err = prepareRepoCommit(repo, tmpDir, repoPath, opts); err != nil { |
|
|
|
|
return fmt.Errorf("prepareRepoCommit: %v", err) |
|
|
|
|
} |
|
|
|
|
} else if com.IsSliceContainsStr(Licenses, license) { |
|
|
|
|
if err = ioutil.WriteFile(targetPath, |
|
|
|
|
bindata.MustAsset(path.Join("conf/license", license)), 0644); err != nil { |
|
|
|
|
return fmt.Errorf("generate license: %v", err) |
|
|
|
|
|
|
|
|
|
// Apply changes and commit.
|
|
|
|
|
if err = initRepoCommit(tmpDir, u.NewGitSig()); err != nil { |
|
|
|
|
return fmt.Errorf("initRepoCommit: %v", err) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
delete(fileName, "license") |
|
|
|
|
repo.IsBare = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Re-fetch the repository from database before updating it (else it would
|
|
|
|
@ -582,23 +618,15 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, initRe |
|
|
|
|
if repo, err = getRepositoryByID(e, repo.ID); err != nil { |
|
|
|
|
return fmt.Errorf("getRepositoryByID: %v", err) |
|
|
|
|
} |
|
|
|
|
if len(fileName) == 0 { |
|
|
|
|
repo.IsBare = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
repo.DefaultBranch = "master" |
|
|
|
|
if err = updateRepository(e, repo, false); err != nil { |
|
|
|
|
return fmt.Errorf("updateRepository: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Ignore init process if user choose not to.
|
|
|
|
|
if len(fileName) == 0 { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Apply changes and commit.
|
|
|
|
|
return initRepoCommit(tmpDir, u.NewGitSig()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) { |
|
|
|
|
if err = IsUsableName(repo.Name); err != nil { |
|
|
|
|
return err |
|
|
|
@ -642,14 +670,14 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// CreateRepository creates a repository for given user or organization.
|
|
|
|
|
func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) { |
|
|
|
|
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) { |
|
|
|
|
repo := &Repository{ |
|
|
|
|
OwnerID: u.Id, |
|
|
|
|
Owner: u, |
|
|
|
|
Name: name, |
|
|
|
|
LowerName: strings.ToLower(name), |
|
|
|
|
Description: desc, |
|
|
|
|
IsPrivate: isPrivate, |
|
|
|
|
Name: opts.Name, |
|
|
|
|
LowerName: strings.ToLower(opts.Name), |
|
|
|
|
Description: opts.Description, |
|
|
|
|
IsPrivate: opts.IsPrivate, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sess := x.NewSession() |
|
|
|
@ -663,9 +691,9 @@ func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMi |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// No need for init mirror.
|
|
|
|
|
if !isMirror { |
|
|
|
|
if !opts.IsMirror { |
|
|
|
|
repoPath := RepoPath(u.Name, repo.Name) |
|
|
|
|
if err = initRepository(sess, repoPath, u, repo, initReadme, lang, license); err != nil { |
|
|
|
|
if err = initRepository(sess, repoPath, u, repo, opts); err != nil { |
|
|
|
|
if err2 := os.RemoveAll(repoPath); err2 != nil { |
|
|
|
|
log.Error(4, "initRepository: %v", err) |
|
|
|
|
return nil, fmt.Errorf( |
|
|
|
|