diff --git a/models/repo.go b/models/repo.go index cf8aff110..1ba8d500e 100644 --- a/models/repo.go +++ b/models/repo.go @@ -163,6 +163,7 @@ func NewRepoContext() { type Repository struct { ID int64 `xorm:"pk autoincr"` OwnerID int64 `xorm:"UNIQUE(s)"` + OwnerName string `xorm:"-"` Owner *User `xorm:"-"` LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` Name string `xorm:"INDEX NOT NULL"` @@ -223,9 +224,17 @@ func (repo *Repository) MustOwner() *User { return repo.mustOwner(x) } +// MustOwnerName always returns valid owner name to avoid +// conceptually impossible error handling. +// It returns "error" and logs error details when error +// occurs. +func (repo *Repository) MustOwnerName() string { + return repo.mustOwnerName(x) +} + // FullName returns the repository full name func (repo *Repository) FullName() string { - return repo.MustOwner().Name + "/" + repo.Name + return repo.MustOwnerName() + "/" + repo.Name } // HTMLURL returns the repository HTML URL @@ -477,6 +486,41 @@ func (repo *Repository) mustOwner(e Engine) *User { return repo.Owner } +func (repo *Repository) getOwnerName(e Engine) error { + if len(repo.OwnerName) > 0 { + return nil + } + + if repo.Owner != nil { + repo.OwnerName = repo.Owner.Name + return nil + } + + u := new(User) + has, err := e.ID(repo.OwnerID).Cols("name").Get(u) + if err != nil { + return err + } else if !has { + return ErrUserNotExist{repo.OwnerID, "", 0} + } + repo.OwnerName = u.Name + return nil +} + +// GetOwnerName returns the repository owner name +func (repo *Repository) GetOwnerName() error { + return repo.getOwnerName(x) +} + +func (repo *Repository) mustOwnerName(e Engine) string { + if err := repo.getOwnerName(e); err != nil { + log.Error(4, "Error loading repository owner name: %v", err) + return "error" + } + + return repo.OwnerName +} + // ComposeMetas composes a map of metas for rendering external issue tracker URL. func (repo *Repository) ComposeMetas() map[string]string { unit, err := repo.GetUnit(UnitTypeExternalTracker) @@ -588,7 +632,7 @@ func (repo *Repository) GetBaseRepo() (err error) { } func (repo *Repository) repoPath(e Engine) string { - return RepoPath(repo.mustOwner(e).Name, repo.Name) + return RepoPath(repo.mustOwnerName(e), repo.Name) } // RepoPath returns the repository path @@ -2133,7 +2177,7 @@ func ReinitMissingRepositories() error { // SyncRepositoryHooks rewrites all repositories' pre-receive, update and post-receive hooks // to make sure the binary and custom conf path are up-to-date. func SyncRepositoryHooks() error { - return x.Where("id > 0").Iterate(new(Repository), + return x.Cols("owner_id", "name").Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { if err := createDelegateHooks(bean.(*Repository).RepoPath()); err != nil { return fmt.Errorf("SyncRepositoryHook: %v", err) diff --git a/models/wiki.go b/models/wiki.go index 3e0d1b9ce..4637a449c 100644 --- a/models/wiki.go +++ b/models/wiki.go @@ -67,7 +67,7 @@ func WikiPath(userName, repoName string) string { // WikiPath returns wiki data path for given repository. func (repo *Repository) WikiPath() string { - return WikiPath(repo.MustOwner().Name, repo.Name) + return WikiPath(repo.MustOwnerName(), repo.Name) } // HasWiki returns true if repository has wiki.