@ -20,11 +20,28 @@ type LanguageStat struct {
CommitID string
CommitID string
IsPrimary bool
IsPrimary bool
Language string ` xorm:"VARCHAR(30) UNIQUE(s) INDEX NOT NULL" `
Language string ` xorm:"VARCHAR(30) UNIQUE(s) INDEX NOT NULL" `
Percentage float32 ` xorm:"NUMERIC(5,2) NOT NULL DEFAULT 0" `
Percentage float32 ` xorm:"-" `
Size int64 ` xorm:"NOT NULL DEFAULT 0" `
Color string ` xorm:"-" `
Color string ` xorm:"-" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX CREATED" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX CREATED" `
}
}
// specialLanguages defines list of languages that are excluded from the calculation
// unless they are the only language present in repository. Only languages which under
// normal circumstances are not considered to be code should be listed here.
var specialLanguages = map [ string ] struct { } {
"XML" : { } ,
"JSON" : { } ,
"TOML" : { } ,
"YAML" : { } ,
"INI" : { } ,
"SQL" : { } ,
"SVG" : { } ,
"Text" : { } ,
"Markdown" : { } ,
"other" : { } ,
}
// LanguageStatList defines a list of language statistics
// LanguageStatList defines a list of language statistics
type LanguageStatList [ ] * LanguageStat
type LanguageStatList [ ] * LanguageStat
@ -34,12 +51,53 @@ func (stats LanguageStatList) loadAttributes() {
}
}
}
}
func ( stats LanguageStatList ) getLanguagePercentages ( ) map [ string ] float32 {
langPerc := make ( map [ string ] float32 )
var otherPerc float32 = 100
var total int64
// Check that repository has at least one non-special language
var skipSpecial bool
for _ , stat := range stats {
if _ , ok := specialLanguages [ stat . Language ] ; ! ok {
skipSpecial = true
break
}
}
for _ , stat := range stats {
// Exclude specific languages from percentage calculation
if _ , ok := specialLanguages [ stat . Language ] ; ok && skipSpecial {
continue
}
total += stat . Size
}
if total > 0 {
for _ , stat := range stats {
// Exclude specific languages from percentage calculation
if _ , ok := specialLanguages [ stat . Language ] ; ok && skipSpecial {
continue
}
perc := float32 ( math . Round ( float64 ( stat . Size ) / float64 ( total ) * 1000 ) / 10 )
if perc <= 0.1 {
continue
}
otherPerc -= perc
langPerc [ stat . Language ] = perc
}
otherPerc = float32 ( math . Round ( float64 ( otherPerc ) * 10 ) / 10 )
} else {
otherPerc = 100
}
if otherPerc > 0 {
langPerc [ "other" ] = otherPerc
}
return langPerc
}
func ( repo * Repository ) getLanguageStats ( e Engine ) ( LanguageStatList , error ) {
func ( repo * Repository ) getLanguageStats ( e Engine ) ( LanguageStatList , error ) {
stats := make ( LanguageStatList , 0 , 6 )
stats := make ( LanguageStatList , 0 , 6 )
if err := e . Where ( "`repo_id` = ?" , repo . ID ) . Desc ( "`percentage`" ) . Find ( & stats ) ; err != nil {
if err := e . Where ( "`repo_id` = ?" , repo . ID ) . Desc ( "`siz e`" ) . Find ( & stats ) ; err != nil {
return nil , err
return nil , err
}
}
stats . loadAttributes ( )
return stats , nil
return stats , nil
}
}
@ -54,13 +112,18 @@ func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error)
if err != nil {
if err != nil {
return nil , err
return nil , err
}
}
perc := stats . getLanguagePercentages ( )
topstats := make ( LanguageStatList , 0 , limit )
topstats := make ( LanguageStatList , 0 , limit )
var other float32
var other float32
for i := range stats {
for i := range stats {
if _ , ok := perc [ stats [ i ] . Language ] ; ! ok {
continue
}
if stats [ i ] . Language == "other" || len ( topstats ) >= limit {
if stats [ i ] . Language == "other" || len ( topstats ) >= limit {
other += stats [ i ] . Percentage
other += perc [ stats [ i ] . Language ]
continue
continue
}
}
stats [ i ] . Percentage = perc [ stats [ i ] . Language ]
topstats = append ( topstats , stats [ i ] )
topstats = append ( topstats , stats [ i ] )
}
}
if other > 0 {
if other > 0 {
@ -71,11 +134,12 @@ func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error)
Percentage : float32 ( math . Round ( float64 ( other ) * 10 ) / 10 ) ,
Percentage : float32 ( math . Round ( float64 ( other ) * 10 ) / 10 ) ,
} )
} )
}
}
topstats . loadAttributes ( )
return topstats , nil
return topstats , nil
}
}
// UpdateLanguageStats updates the language statistics for repository
// UpdateLanguageStats updates the language statistics for repository
func ( repo * Repository ) UpdateLanguageStats ( commitID string , stats map [ string ] float32 ) error {
func ( repo * Repository ) UpdateLanguageStats ( commitID string , stats map [ string ] int64 ) error {
sess := x . NewSession ( )
sess := x . NewSession ( )
if err := sess . Begin ( ) ; err != nil {
if err := sess . Begin ( ) ; err != nil {
return err
return err
@ -87,15 +151,15 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
return err
return err
}
}
var topLang string
var topLang string
var p float32
var s int64
for lang , perc := range stats {
for lang , size := range stats {
if perc > p {
if size > s {
p = perc
s = size
topLang = strings . ToLower ( lang )
topLang = strings . ToLower ( lang )
}
}
}
}
for lang , perc := range stats {
for lang , size := range stats {
upd := false
upd := false
llang := strings . ToLower ( lang )
llang := strings . ToLower ( lang )
for _ , s := range oldstats {
for _ , s := range oldstats {
@ -103,8 +167,8 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
if strings . ToLower ( s . Language ) == llang {
if strings . ToLower ( s . Language ) == llang {
s . CommitID = commitID
s . CommitID = commitID
s . IsPrimary = llang == topLang
s . IsPrimary = llang == topLang
s . Percentage = perc
s . Size = size
if _ , err := sess . ID ( s . ID ) . Cols ( "`commit_id`" , "`percentag e`" , "`is_primary`" ) . Update ( s ) ; err != nil {
if _ , err := sess . ID ( s . ID ) . Cols ( "`commit_id`" , "`siz e`" , "`is_primary`" ) . Update ( s ) ; err != nil {
return err
return err
}
}
upd = true
upd = true
@ -114,11 +178,11 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
// Insert new language
// Insert new language
if ! upd {
if ! upd {
if _ , err := sess . Insert ( & LanguageStat {
if _ , err := sess . Insert ( & LanguageStat {
RepoID : repo . ID ,
RepoID : repo . ID ,
CommitID : commitID ,
CommitID : commitID ,
IsPrimary : llang == topLang ,
IsPrimary : llang == topLang ,
Language : lang ,
Language : lang ,
Percentage : perc ,
Size : size ,
} ) ; err != nil {
} ) ; err != nil {
return err
return err
}
}
@ -153,7 +217,7 @@ func CopyLanguageStat(originalRepo, destRepo *Repository) error {
return err
return err
}
}
RepoLang := make ( LanguageStatList , 0 , 6 )
RepoLang := make ( LanguageStatList , 0 , 6 )
if err := sess . Where ( "`repo_id` = ?" , originalRepo . ID ) . Desc ( "`percentag e`" ) . Find ( & RepoLang ) ; err != nil {
if err := sess . Where ( "`repo_id` = ?" , originalRepo . ID ) . Desc ( "`siz e`" ) . Find ( & RepoLang ) ; err != nil {
return err
return err
}
}
if len ( RepoLang ) > 0 {
if len ( RepoLang ) > 0 {