Browse Source

Implementation of the size of repo

pull/3631/head
aaaa 9 years ago
parent
commit
408e5f4c92
  1. 144
      models/repo.go
  2. 6
      models/update.go
  3. 3
      modules/template/template.go
  4. 2
      templates/admin/repo/list.tmpl

144
models/repo.go

@ -5,10 +5,12 @@
package models
import (
"bufio"
"bytes"
"errors"
"fmt"
"html/template"
"io"
"io/ioutil"
"os"
"os/exec"
@ -16,6 +18,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"time"
@ -194,6 +197,7 @@ type Repository struct {
IsFork bool `xorm:"NOT NULL DEFAULT false"`
ForkID int64
BaseRepo *Repository `xorm:"-"`
RepoSize int64 `xorm:"NOT NULL DEFAULT 0"`
Created time.Time `xorm:"-"`
CreatedUnix int64
@ -427,6 +431,19 @@ func (repo *Repository) IsOwnedBy(userID int64) bool {
return repo.OwnerID == userID
}
func (repo *Repository) GetRepoSize() int64 {
return repo.RepoSize
}
func (repo *Repository) ComputeRepoSize() (err error) {
repoInfoSize, err := GitRepoSize(repo.RepoPath())
if err != nil {
return err
}
repo.RepoSize = repoInfoSize.Size + repoInfoSize.SizePack
return nil
}
// CanBeForked returns true if repository meets the requirements of being forked.
func (repo *Repository) CanBeForked() bool {
return !repo.IsBare
@ -674,6 +691,11 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
}
err = repo.ComputeRepoSize()
if err != nil {
return repo, fmt.Errorf("ComputeRepoSize: %v", err)
}
if opts.IsMirror {
if _, err = x.InsertOne(&Mirror{
RepoID: repo.ID,
@ -1267,6 +1289,11 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err)
}
}
err = repo.ComputeRepoSize()
if err != nil {
return fmt.Errorf("ComputeRepoSize: %v", err)
}
}
return nil
@ -1665,6 +1692,122 @@ func GitGcRepos() error {
})
}
// Maybe move this to gogits/git-module
type CountObject struct {
Count int
Size int64
InPack int64
Packs int
SizePack int64
PrunePack int
Garbage int
SizeGarbage int
}
const STAT_COUNT = "count: "
const STAT_SIZE = "size: "
const STAT_INPACK = "in-pack: "
const STAT_PACKS = "packs: "
const STAT_SIZEPACK = "size-pack: "
const STAT_PRUNEPACKAGE = "prune-package: "
const STAT_GARBAGE = "garbage: "
const STAT_SIZEGARBAGE = "size-garbage: "
func GitRepoSize(repoPath string) (*CountObject, error) {
var cmd *exec.Cmd
cmd = exec.Command("git", "count-objects", "-v")
cmd.Dir = repoPath
cmd.Stderr = os.Stderr
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("StdoutPipe: %v", err)
}
if err = cmd.Start(); err != nil {
return nil, fmt.Errorf("Start: %v", err)
}
repoSize, err := ParseSize(stdout)
if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err)
}
if err = cmd.Wait(); err != nil {
return nil, fmt.Errorf("Wait: %v", err)
}
return repoSize, nil
}
func ParseSize(reader io.Reader) (*CountObject, error) {
repoSize := &CountObject{}
input := bufio.NewReader(reader)
isEOF := false
for !isEOF {
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
isEOF = true
continue
} else {
return nil, fmt.Errorf("ReadString: %v", err)
}
}
if len(line) > 0 && line[len(line)-1] == '\n' {
// Remove line break.
line = line[:len(line)-1]
}
log.Info(line)
switch {
case strings.HasPrefix(line, STAT_COUNT):
repoSize.Count, err = strconv.Atoi(line[7:])
case strings.HasPrefix(line, STAT_SIZE):
repoSize.Size, err = strconv.ParseInt(line[6:], 10, 64)
case strings.HasPrefix(line, STAT_INPACK):
repoSize.InPack, err = strconv.ParseInt(line[9:], 10, 64)
case strings.HasPrefix(line, STAT_PACKS):
repoSize.Packs, err = strconv.Atoi(line[7:])
case strings.HasPrefix(line, STAT_SIZEPACK):
repoSize.SizePack, err = strconv.ParseInt(line[11:], 10, 64)
case strings.HasPrefix(line, STAT_PRUNEPACKAGE):
repoSize.PrunePack, err = strconv.Atoi(line[16:])
case strings.HasPrefix(line, STAT_GARBAGE):
repoSize.Garbage, err = strconv.Atoi(line[9:])
case strings.HasPrefix(line, STAT_SIZEGARBAGE):
repoSize.SizeGarbage, err = strconv.Atoi(line[14:])
}
if err != nil {
log.Error(4, "Parsing count-objects failed: %v", err)
return nil, err
}
}
return repoSize, nil
}
func UpdateRepoSize(repoUserName, repoName string) error {
log.Info("Compute Size of %s - %s", repoUserName, repoName)
repoPath := RepoPath(repoUserName, repoName)
repoInfoSize, err := GitRepoSize(repoPath)
if err != nil {
return err
}
repoSize := repoInfoSize.Size + repoInfoSize.SizePack
log.Info(strconv.FormatInt(repoSize, 10))
sess := x.NewSession()
defer sessionRelease(sess)
if err = sess.Begin(); err != nil {
return nil
}
if _, err = sess.Exec("UPDATE `repository` SET repo_size=? WHERE name=?", repoSize, repoName); err != nil {
return fmt.Errorf("Update repo size failed: %v", err)
}
return sess.Commit()
}
type repoChecker struct {
querySQL, correctSQL string
desc string
@ -2032,6 +2175,7 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
DefaultBranch: oldRepo.DefaultBranch,
IsPrivate: oldRepo.IsPrivate,
IsFork: true,
RepoSize: oldRepo.RepoSize,
ForkID: oldRepo.ID,
}

6
models/update.go

@ -167,5 +167,11 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
}); err != nil {
return fmt.Errorf("CommitRepoAction (branch): %v", err)
}
// Compute repo size
if err := UpdateRepoSize(opts.RepoUserName, opts.RepoName); err != nil {
return fmt.Errorf("Update repo size failed: %v", err)
}
return nil
}

3
modules/template/template.go

@ -75,6 +75,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 {

2
templates/admin/repo/list.tmpl

@ -22,6 +22,7 @@
<th>{{.i18n.Tr "admin.repos.watches"}}</th>
<th>{{.i18n.Tr "admin.repos.stars"}}</th>
<th>{{.i18n.Tr "admin.repos.issues"}}</th>
<th>Size</th>
<th>{{.i18n.Tr "admin.users.created"}}</th>
<th>{{.i18n.Tr "admin.notices.op"}}</th>
</tr>
@ -36,6 +37,7 @@
<td>{{.NumWatches}}</td>
<td>{{.NumStars}}</td>
<td>{{.NumIssues}}</td>
<td>{{SizeFmt .RepoSize}}</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…
Cancel
Save