+66
knotserver/git/language.go
+66
knotserver/git/language.go
···
1
+
package git
2
+
3
+
import (
4
+
"context"
5
+
"path"
6
+
7
+
"github.com/go-enry/go-enry/v2"
8
+
"github.com/go-git/go-git/v5/plumbing/object"
9
+
)
10
+
11
+
type LangBreakdown map[string]int64
12
+
13
+
func (g *GitRepo) AnalyzeLanguages(ctx context.Context) (LangBreakdown, error) {
14
+
sizes := make(map[string]int64)
15
+
err := g.Walk(ctx, "", func(node object.TreeEntry, parent *object.Tree, root string) error {
16
+
filepath := path.Join(root, node.Name)
17
+
18
+
content, err := g.FileContentN(filepath, 16*1024) // 16KB
19
+
if err != nil {
20
+
return nil
21
+
}
22
+
23
+
if enry.IsGenerated(filepath, content) {
24
+
return nil
25
+
}
26
+
27
+
language := analyzeLanguage(node, content)
28
+
if group := enry.GetLanguageGroup(language); group != "" {
29
+
language = group
30
+
}
31
+
32
+
langType := enry.GetLanguageType(language)
33
+
if langType != enry.Programming && langType != enry.Markup && langType != enry.Unknown {
34
+
return nil
35
+
}
36
+
37
+
sz, _ := parent.Size(node.Name)
38
+
sizes[language] += sz
39
+
40
+
return nil
41
+
})
42
+
43
+
if err != nil {
44
+
return nil, err
45
+
}
46
+
47
+
return sizes, nil
48
+
}
49
+
50
+
func analyzeLanguage(node object.TreeEntry, content []byte) string {
51
+
language, ok := enry.GetLanguageByExtension(node.Name)
52
+
if ok {
53
+
return language
54
+
}
55
+
56
+
language, ok = enry.GetLanguageByFilename(node.Name)
57
+
if ok {
58
+
return language
59
+
}
60
+
61
+
if len(content) == 0 {
62
+
return enry.OtherLanguage
63
+
}
64
+
65
+
return enry.GetLanguage(node.Name, content)
66
+
}
+2
-51
knotserver/routes.go
+2
-51
knotserver/routes.go
···
13
13
"net/http"
14
14
"net/url"
15
15
"os"
16
-
"path"
17
16
"path/filepath"
18
17
"strconv"
19
18
"strings"
···
23
22
securejoin "github.com/cyphar/filepath-securejoin"
24
23
"github.com/gliderlabs/ssh"
25
24
"github.com/go-chi/chi/v5"
26
-
"github.com/go-enry/go-enry/v2"
27
25
gogit "github.com/go-git/go-git/v5"
28
26
"github.com/go-git/go-git/v5/plumbing"
29
27
"github.com/go-git/go-git/v5/plumbing/object"
···
785
783
return
786
784
}
787
785
788
-
sizes := make(map[string]int64)
789
-
790
786
ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second)
791
787
defer cancel()
792
788
793
-
err = gr.Walk(ctx, "", func(node object.TreeEntry, parent *object.Tree, root string) error {
794
-
filepath := path.Join(root, node.Name)
795
-
796
-
content, err := gr.FileContentN(filepath, 16*1024) // 16KB
797
-
if err != nil {
798
-
return nil
799
-
}
800
-
801
-
if enry.IsGenerated(filepath, content) {
802
-
return nil
803
-
}
804
-
805
-
language := analyzeLanguage(node, content)
806
-
if group := enry.GetLanguageGroup(language); group != "" {
807
-
language = group
808
-
}
809
-
810
-
langType := enry.GetLanguageType(language)
811
-
if langType != enry.Programming && langType != enry.Markup && langType != enry.Unknown {
812
-
return nil
813
-
}
814
-
815
-
sz, _ := parent.Size(node.Name)
816
-
sizes[language] += sz
817
-
818
-
return nil
819
-
})
789
+
sizes, err := gr.AnalyzeLanguages(ctx)
820
790
if err != nil {
821
-
l.Error("failed to recurse file tree", "error", err.Error())
791
+
l.Error("failed to analyze languages", "error", err.Error())
822
792
writeError(w, err.Error(), http.StatusNoContent)
823
793
return
824
794
}
···
826
796
resp := types.RepoLanguageResponse{Languages: sizes}
827
797
828
798
writeJSON(w, resp)
829
-
return
830
-
}
831
-
832
-
func analyzeLanguage(node object.TreeEntry, content []byte) string {
833
-
language, ok := enry.GetLanguageByExtension(node.Name)
834
-
if ok {
835
-
return language
836
-
}
837
-
838
-
language, ok = enry.GetLanguageByFilename(node.Name)
839
-
if ok {
840
-
return language
841
-
}
842
-
843
-
if len(content) == 0 {
844
-
return enry.OtherLanguage
845
-
}
846
-
847
-
return enry.GetLanguage(node.Name, content)
848
799
}
849
800
850
801
func (h *Handle) RepoForkSync(w http.ResponseWriter, r *http.Request) {