mirror of https://github.com/go-gitea/gitea
Move some repository methods from models to modules/repository (#9353)
* Move some repository methods from models to modules/repository * fix testpull/8419/head^2
parent
2904abdc22
commit
7b2ff82d20
@ -0,0 +1,223 @@ |
||||
// 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" |
||||
"os" |
||||
"path" |
||||
"strings" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/models" |
||||
"code.gitea.io/gitea/modules/git" |
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/setting" |
||||
api "code.gitea.io/gitea/modules/structs" |
||||
"code.gitea.io/gitea/modules/timeutil" |
||||
"gopkg.in/ini.v1" |
||||
) |
||||
|
||||
/* |
||||
GitHub, GitLab, Gogs: *.wiki.git |
||||
BitBucket: *.git/wiki |
||||
*/ |
||||
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"} |
||||
|
||||
// wikiRemoteURL returns accessible repository URL for wiki if exists.
|
||||
// Otherwise, it returns an empty string.
|
||||
func wikiRemoteURL(remote string) string { |
||||
remote = strings.TrimSuffix(remote, ".git") |
||||
for _, suffix := range commonWikiURLSuffixes { |
||||
wikiURL := remote + suffix |
||||
if git.IsRepoURLAccessible(wikiURL) { |
||||
return wikiURL |
||||
} |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// MigrateRepositoryGitData starts migrating git related data after created migrating repository
|
||||
func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opts api.MigrateRepoOption) (*models.Repository, error) { |
||||
repoPath := models.RepoPath(u.Name, opts.RepoName) |
||||
|
||||
if u.IsOrganization() { |
||||
t, err := u.GetOwnerTeam() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
repo.NumWatches = t.NumMembers |
||||
} else { |
||||
repo.NumWatches = 1 |
||||
} |
||||
|
||||
migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second |
||||
|
||||
var err error |
||||
if err = os.RemoveAll(repoPath); err != nil { |
||||
return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) |
||||
} |
||||
|
||||
if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ |
||||
Mirror: true, |
||||
Quiet: true, |
||||
Timeout: migrateTimeout, |
||||
}); err != nil { |
||||
return repo, fmt.Errorf("Clone: %v", err) |
||||
} |
||||
|
||||
if opts.Wiki { |
||||
wikiPath := models.WikiPath(u.Name, opts.RepoName) |
||||
wikiRemotePath := wikiRemoteURL(opts.CloneAddr) |
||||
if len(wikiRemotePath) > 0 { |
||||
if err := os.RemoveAll(wikiPath); err != nil { |
||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) |
||||
} |
||||
|
||||
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ |
||||
Mirror: true, |
||||
Quiet: true, |
||||
Timeout: migrateTimeout, |
||||
Branch: "master", |
||||
}); err != nil { |
||||
log.Warn("Clone wiki: %v", err) |
||||
if err := os.RemoveAll(wikiPath); err != nil { |
||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath) |
||||
if err != nil { |
||||
return repo, fmt.Errorf("OpenRepository: %v", err) |
||||
} |
||||
defer gitRepo.Close() |
||||
|
||||
repo.IsEmpty, err = gitRepo.IsEmpty() |
||||
if err != nil { |
||||
return repo, fmt.Errorf("git.IsEmpty: %v", err) |
||||
} |
||||
|
||||
if !opts.Releases && !repo.IsEmpty { |
||||
// Try to get HEAD branch and set it as default branch.
|
||||
headBranch, err := gitRepo.GetHEADBranch() |
||||
if err != nil { |
||||
return repo, fmt.Errorf("GetHEADBranch: %v", err) |
||||
} |
||||
if headBranch != nil { |
||||
repo.DefaultBranch = headBranch.Name |
||||
} |
||||
|
||||
if err = SyncReleasesWithTags(repo, gitRepo); err != nil { |
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err) |
||||
} |
||||
} |
||||
|
||||
if err = repo.UpdateSize(); err != nil { |
||||
log.Error("Failed to update size for repository: %v", err) |
||||
} |
||||
|
||||
if opts.Mirror { |
||||
if err = models.InsertMirror(&models.Mirror{ |
||||
RepoID: repo.ID, |
||||
Interval: setting.Mirror.DefaultInterval, |
||||
EnablePrune: true, |
||||
NextUpdateUnix: timeutil.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval), |
||||
}); err != nil { |
||||
return repo, fmt.Errorf("InsertOne: %v", err) |
||||
} |
||||
|
||||
repo.IsMirror = true |
||||
err = models.UpdateRepository(repo, false) |
||||
} else { |
||||
repo, err = CleanUpMigrateInfo(repo) |
||||
} |
||||
|
||||
return repo, err |
||||
} |
||||
|
||||
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
|
||||
// This also removes possible user credentials.
|
||||
func cleanUpMigrateGitConfig(configPath string) error { |
||||
cfg, err := ini.Load(configPath) |
||||
if err != nil { |
||||
return fmt.Errorf("open config file: %v", err) |
||||
} |
||||
cfg.DeleteSection("remote \"origin\"") |
||||
if err = cfg.SaveToIndent(configPath, "\t"); err != nil { |
||||
return fmt.Errorf("save config file: %v", err) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
|
||||
func CleanUpMigrateInfo(repo *models.Repository) (*models.Repository, error) { |
||||
repoPath := repo.RepoPath() |
||||
if err := models.CreateDelegateHooks(repoPath); err != nil { |
||||
return repo, fmt.Errorf("createDelegateHooks: %v", err) |
||||
} |
||||
if repo.HasWiki() { |
||||
if err := models.CreateDelegateHooks(repo.WikiPath()); err != nil { |
||||
return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err) |
||||
} |
||||
} |
||||
|
||||
_, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath) |
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { |
||||
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) |
||||
} |
||||
|
||||
if repo.HasWiki() { |
||||
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil { |
||||
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err) |
||||
} |
||||
} |
||||
|
||||
return repo, models.UpdateRepository(repo, false) |
||||
} |
||||
|
||||
// SyncReleasesWithTags synchronizes release table with repository tags
|
||||
func SyncReleasesWithTags(repo *models.Repository, gitRepo *git.Repository) error { |
||||
existingRelTags := make(map[string]struct{}) |
||||
opts := models.FindReleasesOptions{IncludeDrafts: true, IncludeTags: true} |
||||
for page := 1; ; page++ { |
||||
rels, err := models.GetReleasesByRepoID(repo.ID, opts, page, 100) |
||||
if err != nil { |
||||
return fmt.Errorf("GetReleasesByRepoID: %v", err) |
||||
} |
||||
if len(rels) == 0 { |
||||
break |
||||
} |
||||
for _, rel := range rels { |
||||
if rel.IsDraft { |
||||
continue |
||||
} |
||||
commitID, err := gitRepo.GetTagCommitID(rel.TagName) |
||||
if err != nil && !git.IsErrNotExist(err) { |
||||
return fmt.Errorf("GetTagCommitID: %v", err) |
||||
} |
||||
if git.IsErrNotExist(err) || commitID != rel.Sha1 { |
||||
if err := models.PushUpdateDeleteTag(repo, rel.TagName); err != nil { |
||||
return fmt.Errorf("PushUpdateDeleteTag: %v", err) |
||||
} |
||||
} else { |
||||
existingRelTags[strings.ToLower(rel.TagName)] = struct{}{} |
||||
} |
||||
} |
||||
} |
||||
tags, err := gitRepo.GetTags() |
||||
if err != nil { |
||||
return fmt.Errorf("GetTags: %v", err) |
||||
} |
||||
for _, tagName := range tags { |
||||
if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok { |
||||
if err := models.PushUpdateAddTag(repo, gitRepo, tagName); err != nil { |
||||
return fmt.Errorf("pushUpdateAddTag: %v", err) |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
Loading…
Reference in new issue