From be6edaddcba1e607884539a250bd19debabba751 Mon Sep 17 00:00:00 2001 From: Jonas Date: Tue, 11 Apr 2017 15:30:15 +0200 Subject: [PATCH] Repo size in admin panel (#1482) * Implementation of the feature to view repository size in admin panel * Move GetRepoSize to git module * Repository.RepoSize -> Repository.Size * RepoSize -> Size in template * Redo a few bits and pieces * Update size when syncing mirror or forking * Remove GetRepoSize * Changed fatal errors to error message * Copy migration code from Gogs * make fmt --- models/migrations/migrations.go | 2 + models/migrations/v28.go | 77 +++++++++++++++++++++++++++++++++ models/repo.go | 25 +++++++++++ models/repo_mirror.go | 5 +++ models/update.go | 4 ++ modules/templates/helper.go | 3 ++ options/locale/locale_en-US.ini | 1 + templates/admin/repo/list.tmpl | 2 + 8 files changed, 119 insertions(+) create mode 100644 models/migrations/v28.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index fee0fef79c..fb7b66cd00 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -104,6 +104,8 @@ var migrations = []Migration{ NewMigration("generate and migrate repo and wiki Git hooks", generateAndMigrateGitHookChains), // v27 -> v28 NewMigration("change mirror interval from hours to time.Duration", convertIntervalToDuration), + // v28 -> v29 + NewMigration("add field for repo size", addRepoSize), } // Migrate database to current version diff --git a/models/migrations/v28.go b/models/migrations/v28.go new file mode 100644 index 0000000000..f7b4cd6e30 --- /dev/null +++ b/models/migrations/v28.go @@ -0,0 +1,77 @@ +// Copyright 2017 The Gogs Authors. All rights reserved. +// Copyright 2017 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + "path/filepath" + "strings" + + "code.gitea.io/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/go-xorm/xorm" +) + +func addRepoSize(x *xorm.Engine) (err error) { + log.Info("This migration could take up to minutes, please be patient.") + type Repository struct { + ID int64 + OwnerID int64 + Name string + Size int64 + } + type User struct { + ID int64 + Name string + } + if err = x.Sync2(new(Repository)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + + // For the sake of SQLite3, we can't use x.Iterate here. + offset := 0 + for { + repos := make([]*Repository, 0, 10) + if err = x.Sql(fmt.Sprintf("SELECT * FROM `repository` ORDER BY id ASC LIMIT 10 OFFSET %d", offset)). + Find(&repos); err != nil { + return fmt.Errorf("select repos [offset: %d]: %v", offset, err) + } + log.Trace("Select [offset: %d, repos: %d]", offset, len(repos)) + if len(repos) == 0 { + break + } + offset += 10 + + for _, repo := range repos { + if repo.Name == "." || repo.Name == ".." { + continue + } + + user := new(User) + has, err := x.Where("id = ?", repo.OwnerID).Get(user) + if err != nil { + return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) + } else if !has { + continue + } + + repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git" + countObject, err := git.GetRepoSize(repoPath) + if err != nil { + log.Warn("GetRepoSize: %v", err) + continue + } + + repo.Size = countObject.Size + countObject.SizePack + if _, err = x.Id(repo.ID).Cols("size").Update(repo); err != nil { + return fmt.Errorf("update size: %v", err) + } + } + } + return nil +} diff --git a/models/repo.go b/models/repo.go index c654356916..a35a7597f4 100644 --- a/models/repo.go +++ b/models/repo.go @@ -207,6 +207,7 @@ type Repository struct { IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"` ForkID int64 `xorm:"INDEX"` BaseRepo *Repository `xorm:"-"` + Size int64 `xorm:"NOT NULL DEFAULT 0"` Created time.Time `xorm:"-"` CreatedUnix int64 `xorm:"INDEX"` @@ -546,6 +547,18 @@ func (repo *Repository) IsOwnedBy(userID int64) bool { return repo.OwnerID == userID } +// UpdateSize updates the repository size, calculating it using git.GetRepoSize +func (repo *Repository) UpdateSize() error { + repoInfoSize, err := git.GetRepoSize(repo.RepoPath()) + if err != nil { + return fmt.Errorf("UpdateSize: %v", err) + } + + repo.Size = repoInfoSize.Size + repoInfoSize.SizePack + _, err = x.ID(repo.ID).Cols("size").Update(repo) + return err +} + // CanBeForked returns true if repository meets the requirements of being forked. func (repo *Repository) CanBeForked() bool { return !repo.IsBare @@ -810,6 +823,10 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { } } + if err = repo.UpdateSize(); err != nil { + log.Error(4, "Failed to update size for repository: %v", err) + } + if opts.IsMirror { if _, err = x.InsertOne(&Mirror{ RepoID: repo.ID, @@ -1464,6 +1481,10 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err) } } + + if err = repo.UpdateSize(); err != nil { + log.Error(4, "Failed to update size for repository: %v", err) + } } return nil @@ -2171,6 +2192,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit return nil, err } + if err = repo.UpdateSize(); err != nil { + log.Error(4, "Failed to update size for repository: %v", err) + } + // Copy LFS meta objects in new session sess2 := x.NewSession() defer sessionRelease(sess2) diff --git a/models/repo_mirror.go b/models/repo_mirror.go index 67ae449bde..8a97879253 100644 --- a/models/repo_mirror.go +++ b/models/repo_mirror.go @@ -147,6 +147,11 @@ func (m *Mirror) runSync() bool { } return false } + + if err := m.Repo.UpdateSize(); err != nil { + log.Error(4, "Failed to update size for mirror repository: %v", err) + } + if m.Repo.HasWiki() { if _, stderr, err := process.GetManager().ExecDir( timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath), diff --git a/models/update.go b/models/update.go index 3cb0608594..b3a8a1c9fb 100644 --- a/models/update.go +++ b/models/update.go @@ -101,6 +101,10 @@ func PushUpdate(opts PushUpdateOptions) (err error) { return fmt.Errorf("GetRepositoryByName: %v", err) } + if err = repo.UpdateSize(); err != nil { + log.Error(4, "Failed to update size for repository: %v", err) + } + // Push tags. if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { if err := CommitRepoAction(CommitRepoActionOptions{ diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 2e756ce364..51877f8039 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -82,6 +82,9 @@ func NewFuncMap() []template.FuncMap { "DateFmtShort": func(t time.Time) string { return t.Format("Jan 02, 2006") }, + "SizeFmt": func(s int64) string { + return base.FileSize(s) + }, "List": List, "SubStr": func(str string, start, length int) string { if len(str) == 0 { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index cfb4da30ae..cb39ec8571 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1119,6 +1119,7 @@ repos.private = Private repos.watches = Watches repos.stars = Stars repos.issues = Issues +repos.size = Size auths.auth_manage_panel = Authentication Manage Panel auths.new = Add New Source diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index ffdbd5bfb8..aeaecf8dfb 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -20,6 +20,7 @@ {{.i18n.Tr "admin.repos.watches"}} {{.i18n.Tr "admin.repos.stars"}} {{.i18n.Tr "admin.repos.issues"}} + {{.i18n.Tr "admin.repos.size"}} {{.i18n.Tr "admin.users.created"}} {{.i18n.Tr "admin.notices.op"}} @@ -34,6 +35,7 @@ {{.NumWatches}} {{.NumStars}} {{.NumIssues}} + {{SizeFmt .Size}} {{DateFmtShort .Created}}