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
This commit is contained in:
		
							parent
							
								
									54f0293f0a
								
							
						
					
					
						commit
						be6edaddcb
					
				| @ -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
 | ||||
|  | ||||
							
								
								
									
										77
									
								
								models/migrations/v28.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								models/migrations/v28.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| } | ||||
| @ -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) | ||||
|  | ||||
| @ -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), | ||||
|  | ||||
| @ -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{ | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -20,6 +20,7 @@ | ||||
| 						<th>{{.i18n.Tr "admin.repos.watches"}}</th> | ||||
| 						<th>{{.i18n.Tr "admin.repos.stars"}}</th> | ||||
| 						<th>{{.i18n.Tr "admin.repos.issues"}}</th> | ||||
| 						<th>{{.i18n.Tr "admin.repos.size"}}</th> | ||||
| 						<th>{{.i18n.Tr "admin.users.created"}}</th> | ||||
| 						<th>{{.i18n.Tr "admin.notices.op"}}</th> | ||||
| 					</tr> | ||||
| @ -34,6 +35,7 @@ | ||||
| 							<td>{{.NumWatches}}</td> | ||||
| 							<td>{{.NumStars}}</td> | ||||
| 							<td>{{.NumIssues}}</td> | ||||
| 							<td>{{SizeFmt .Size}}</td> | ||||
| 							<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td> | ||||
| 							<td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Current}}" data-id="{{.ID}}"><i class="trash icon text red"></i></a></td> | ||||
| 						</tr> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user