Browse Source

Limit file contents, results...

- Limit amount of data sent to linguist.LanguageByContents to 512 bytes
   (performance concern, though it is still slow...)

 - Limit amount of results to 8, sum remainder and display as "Other"
   (the widget looks cluttered with a lot of results)

 - Better error handling.
pull/2135/head
tso 9 years ago
parent
commit
8bac1467a1
  1. 103
      routers/repo/view.go

103
routers/repo/view.go

@ -7,7 +7,9 @@ package repo
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os/exec"
"path" "path"
"sort" "sort"
"strconv" "strconv"
@ -203,7 +205,11 @@ func Home(ctx *middleware.Context) {
if err != nil || branchId != lastCommit.ID.String() { if err != nil || branchId != lastCommit.ID.String() {
branchId = lastCommit.ID.String() branchId = lastCommit.ID.String()
} }
Langs := getLanguageStats(ctx, branchId) Langs, tsoErr := getLanguageStats(ctx, branchId)
if tsoErr != nil {
ctx.Handle(500, "*blames tso*", err)
return
}
ctx.Data["LanguageStats"] = Langs ctx.Data["LanguageStats"] = Langs
} }
@ -284,9 +290,12 @@ func Forks(ctx *middleware.Context) {
ctx.HTML(200, FORKS) ctx.HTML(200, FORKS)
} }
func getLanguageStats(ctx *middleware.Context, branchId string) interface{} { func getLanguageStats(ctx *middleware.Context, branchId string) (interface{}, error) {
all_files := linguistlstree(ctx, branchId) all_files, err := linguistlstree(ctx, branchId)
if err != nil {
return nil, err
}
languages := map[string]float64{} languages := map[string]float64{}
var total_size float64 var total_size float64
@ -307,21 +316,29 @@ func getLanguageStats(ctx *middleware.Context, branchId string) interface{} {
sort.Sort(sort.Reverse(sort.Float64Slice(percent))) sort.Sort(sort.Reverse(sort.Float64Slice(percent)))
ret := []*LanguageStat{} ret := []*LanguageStat{}
other := 0.0
default_color := "#ccc" // grey
for i, p := range percent { for i, p := range percent {
// limit result set // limit result set, doesn't look nice when list is huge
if i > 10 { if i >= 8 {
other += p
break break
} }
lang := results[p] lang := results[p]
color := linguist.LanguageColor(lang) color := linguist.LanguageColor(lang)
if color == "" { if color == "" {
color = "#ccc" //grey color = default_color
} }
ret = append(ret, &LanguageStat{Name: lang, ret = append(ret, &LanguageStat{Name: lang,
Percent: fmt.Sprintf("%.2f%%", p), Percent: fmt.Sprintf("%.2f%%", p),
Color: color}) Color: color})
} }
return ret if other > 0.0 {
ret = append(ret, &LanguageStat{Name: "Other",
Percent: fmt.Sprintf("%.2f%%", other),
Color: default_color})
}
return ret, nil
} }
type LanguageStat struct { type LanguageStat struct {
@ -338,27 +355,54 @@ type file struct {
} }
// just some utilities... // just some utilities...
func gitcmd(ctx *middleware.Context, args ...string) string { func gitcmd(ctx *middleware.Context, args ...string) (string, error) {
stdout, _, err := com.ExecCmdDir(ctx.Repo.GitRepo.Path, "git", args...) stdout, _, err := com.ExecCmdDir(ctx.Repo.GitRepo.Path, "git", args...)
tsoErr(ctx, err) if err != nil {
return stdout return "", err
} }
func gitcmdbytes(ctx *middleware.Context, args ...string) []byte { return stdout, nil
stdout, _, err := com.ExecCmdDirBytes(ctx.Repo.GitRepo.Path, "git", args...)
tsoErr(ctx, err)
return stdout
} }
func tsoErr(ctx *middleware.Context, err error) { func gitcatfile(ctx *middleware.Context, hash string) ([]byte, error) {
git := exec.Command("git", "cat-file blob"+hash)
git.Dir = ctx.Repo.GitRepo.Path
stdout, err := git.StdoutPipe()
if err != nil { if err != nil {
ctx.Handle(500, "*blames tso*", err) return nil, err
} }
// please be aware of weirdness, i.e. this error message:
// "read |0: bad file descriptor"
// https://code.google.com/p/go/issues/detail?id=2266
c := make(chan error)
r := make(chan struct{})
blob := make([]byte, 512)
go func() {
git.Start()
r <- struct{}{}
git.Wait()
c <- nil
}()
go func() {
<-r
_, err := stdout.Read(blob)
if err != io.EOF && err != nil {
c <- err
return
}
git.Process.Kill()
c <- nil
}()
err = <-c
return blob, err
} }
// returns every file in a tree // returns every file in a tree
// additionally detecting programming language // additionally detecting programming language
func linguistlstree(ctx *middleware.Context, treeish string) (files []*file) { func linguistlstree(ctx *middleware.Context, treeish string) (files []*file, e error) {
files = []*file{} files = []*file{}
lstext := gitcmd(ctx, "ls-tree", treeish) lstext, err := gitcmd(ctx, "ls-tree", treeish)
if err != nil {
return nil, err
}
for _, ln := range strings.Split(lstext, "\n") { for _, ln := range strings.Split(lstext, "\n") {
fields := strings.Split(ln, " ") fields := strings.Split(ln, " ")
if len(fields) != 3 { if len(fields) != 3 {
@ -375,12 +419,20 @@ func linguistlstree(ctx *middleware.Context, treeish string) (files []*file) {
switch ftype { switch ftype {
case "tree": case "tree":
subdir := linguistlstree(ctx, fhash) subdir, err := linguistlstree(ctx, fhash)
if err != nil {
return nil, err
}
files = append(files, subdir...) files = append(files, subdir...)
case "blob": case "blob":
ssize := gitcmd(ctx, "cat-file", "-s", fhash) ssize, err := gitcmd(ctx, "cat-file", "-s", fhash)
if err != nil {
return nil, err
}
fsize, err := strconv.ParseFloat(strings.TrimSpace(ssize), 64) fsize, err := strconv.ParseFloat(strings.TrimSpace(ssize), 64)
tsoErr(ctx, err) if err != nil {
return nil, err
}
// if it's an empty file don't even waste time // if it's an empty file don't even waste time
if fsize == 0 { if fsize == 0 {
@ -407,7 +459,10 @@ func linguistlstree(ctx *middleware.Context, treeish string) (files []*file) {
} }
hints := linguist.LanguageHints(fname) hints := linguist.LanguageHints(fname)
contents := gitcmdbytes(ctx, "cat-file", "blob", fhash) contents, err := gitcatfile(ctx, fhash)
if err != nil {
return nil, err
}
if linguist.ShouldIgnoreContents(contents) { if linguist.ShouldIgnoreContents(contents) {
continue continue
@ -422,5 +477,5 @@ func linguistlstree(ctx *middleware.Context, treeish string) (files []*file) {
files = append(files, f) files = append(files, f)
} }
} }
return files return files, nil
} }

Loading…
Cancel
Save