diff options
author | Unknwon <u@gogs.io> | 2015-12-08 20:06:12 -0500 |
---|---|---|
committer | Unknwon <u@gogs.io> | 2015-12-08 20:06:12 -0500 |
commit | 120cd4e4716d11f79a7e8c41c066383e579d480a (patch) | |
tree | b25ae1b31ecf5437250c388d55ee940e294a4187 /models/repo.go | |
parent | 1cbd4c01fbfd4e15e36a722c9e2cc19366be3df8 (diff) | |
download | gitea-120cd4e4716d11f79a7e8c41c066383e579d480a.tar.gz gitea-120cd4e4716d11f79a7e8c41c066383e579d480a.zip |
#1984 Better mirror repo management
Diffstat (limited to 'models/repo.go')
-rw-r--r-- | models/repo.go | 118 |
1 files changed, 83 insertions, 35 deletions
diff --git a/models/repo.go b/models/repo.go index 25f66600ab..2a45bdc0b2 100644 --- a/models/repo.go +++ b/models/repo.go @@ -301,6 +301,10 @@ func (repo *Repository) RepoPath() string { return repo.repoPath(x) } +func (repo *Repository) GitConfigPath() string { + return filepath.Join(repo.RepoPath(), "config") +} + func (repo *Repository) RepoLink() string { return setting.AppSubUrl + "/" + repo.MustOwner().Name + "/" + repo.Name } @@ -345,7 +349,7 @@ func (repo *Repository) LocalCopyPath() string { func updateLocalCopy(repoPath, localPath string) error { if !com.IsExist(localPath) { - if err := git.Clone(repoPath, localPath); err != nil { + if err := git.Clone(repoPath, localPath, git.CloneRepoOptions{}); err != nil { return fmt.Errorf("Clone: %v", err) } } else { @@ -484,6 +488,8 @@ type Mirror struct { Interval int // Hour. Updated time.Time `xorm:"UPDATED"` NextUpdate time.Time + + address string `xorm:"-"` } func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { @@ -497,6 +503,61 @@ func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { } } +func (m *Mirror) readAddress() { + if len(m.address) > 0 { + return + } + + cfg, err := ini.Load(m.Repo.GitConfigPath()) + if err != nil { + log.Error(4, "Load: %v", err) + return + } + m.address = cfg.Section("remote \"origin\"").Key("url").Value() +} + +// HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL +// with placeholder <credentials>. +// It will fail for any other forms of clone addresses. +func HandleCloneUserCredentials(url string, mosaics bool) string { + i := strings.Index(url, "@") + if i == -1 { + return url + } + start := strings.Index(url, "://") + if start == -1 { + return url + } + if mosaics { + return url[:start+3] + "<credentials>" + url[i:] + } + return url[:start+3] + url[i+1:] +} + +// Address returns mirror address from Git repository config without credentials. +func (m *Mirror) Address() string { + m.readAddress() + return HandleCloneUserCredentials(m.address, false) +} + +// FullAddress returns mirror address from Git repository config. +func (m *Mirror) FullAddress() string { + m.readAddress() + return m.address +} + +// SaveAddress writes new address to Git repository config. +func (m *Mirror) SaveAddress(addr string) error { + configPath := m.Repo.GitConfigPath() + cfg, err := ini.Load(configPath) + if err != nil { + return fmt.Errorf("Load: %v", err) + } + + cfg.Section("remote \"origin\"").Key("url").SetValue(addr) + return cfg.SaveToIndent(configPath, "\t") +} + func getMirror(e Engine, repoId int64) (*Mirror, error) { m := &Mirror{RepoID: repoId} has, err := e.Get(m) @@ -527,25 +588,6 @@ func createUpdateHook(repoPath string) error { fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)) } -// MirrorRepository creates a mirror repository from source. -func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error { - _, stderr, err := process.ExecTimeout(10*time.Minute, - fmt.Sprintf("MirrorRepository: %s/%s", userName, repoName), - "git", "clone", "--mirror", url, repoPath) - if err != nil { - return errors.New("git clone --mirror: " + stderr) - } - - if _, err = x.InsertOne(&Mirror{ - RepoID: repoId, - Interval: 24, - NextUpdate: time.Now().Add(24 * time.Hour), - }); err != nil { - return err - } - return nil -} - type MigrateRepoOptions struct { Name string Description string @@ -582,29 +624,35 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { repo.NumWatches = 1 } - repo.IsBare = false + os.RemoveAll(repoPath) + if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneRepoOptions{ + Mirror: true, + Quiet: true, + Timeout: 10 * time.Minute, + }); err != nil { + return repo, fmt.Errorf("Clone: %v", err) + } + if opts.IsMirror { - if err = MirrorRepository(repo.ID, u.Name, repo.Name, repoPath, opts.RemoteAddr); err != nil { - return repo, err + if _, err = x.InsertOne(&Mirror{ + RepoID: repo.ID, + Interval: 24, + NextUpdate: time.Now().Add(24 * time.Hour), + }); err != nil { + return repo, fmt.Errorf("InsertOne: %v", err) } + repo.IsMirror = true return repo, UpdateRepository(repo, false) - } else { - os.RemoveAll(repoPath) } - // FIXME: this command could for both migrate and mirror - _, stderr, err := process.ExecTimeout(10*time.Minute, - fmt.Sprintf("MigrateRepository: %s", repoPath), - "git", "clone", "--mirror", "--bare", "--quiet", opts.RemoteAddr, repoPath) - if err != nil { - return repo, fmt.Errorf("git clone --mirror --bare --quiet: %v", stderr) - } else if err = createUpdateHook(repoPath); err != nil { - return repo, fmt.Errorf("create update hook: %v", err) + if err = createUpdateHook(repoPath); err != nil { + return repo, fmt.Errorf("createUpdateHook: %v", err) } // Clean up mirror info which prevents "push --all". - configPath := filepath.Join(repoPath, "/config") + // This also removes possible user credentials. + configPath := repo.GitConfigPath() cfg, err := ini.Load(configPath) if err != nil { return repo, fmt.Errorf("open config file: %v", err) @@ -615,7 +663,7 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { } // Check if repository is empty. - _, stderr, err = com.ExecCmdDir(repoPath, "git", "log", "-1") + _, stderr, err := com.ExecCmdDir(repoPath, "git", "log", "-1") if err != nil { if strings.Contains(stderr, "fatal: bad default revision 'HEAD'") { repo.IsBare = true |