+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"
···
777
775
return
778
776
}
779
777
780
-
sizes := make(map[string]int64)
781
-
782
778
ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second)
783
779
defer cancel()
784
780
785
-
err = gr.Walk(ctx, "", func(node object.TreeEntry, parent *object.Tree, root string) error {
786
-
filepath := path.Join(root, node.Name)
787
-
788
-
content, err := gr.FileContentN(filepath, 16*1024) // 16KB
789
-
if err != nil {
790
-
return nil
791
-
}
792
-
793
-
if enry.IsGenerated(filepath, content) {
794
-
return nil
795
-
}
796
-
797
-
language := analyzeLanguage(node, content)
798
-
if group := enry.GetLanguageGroup(language); group != "" {
799
-
language = group
800
-
}
801
-
802
-
langType := enry.GetLanguageType(language)
803
-
if langType != enry.Programming && langType != enry.Markup && langType != enry.Unknown {
804
-
return nil
805
-
}
806
-
807
-
sz, _ := parent.Size(node.Name)
808
-
sizes[language] += sz
809
-
810
-
return nil
811
-
})
781
+
sizes, err := gr.AnalyzeLanguages(ctx)
812
782
if err != nil {
813
-
l.Error("failed to recurse file tree", "error", err.Error())
783
+
l.Error("failed to analyze languages", "error", err.Error())
814
784
writeError(w, err.Error(), http.StatusNoContent)
815
785
return
816
786
}
···
818
788
resp := types.RepoLanguageResponse{Languages: sizes}
819
789
820
790
writeJSON(w, resp)
821
-
return
822
-
}
823
-
824
-
func analyzeLanguage(node object.TreeEntry, content []byte) string {
825
-
language, ok := enry.GetLanguageByExtension(node.Name)
826
-
if ok {
827
-
return language
828
-
}
829
-
830
-
language, ok = enry.GetLanguageByFilename(node.Name)
831
-
if ok {
832
-
return language
833
-
}
834
-
835
-
if len(content) == 0 {
836
-
return enry.OtherLanguage
837
-
}
838
-
839
-
return enry.GetLanguage(node.Name, content)
840
791
}
841
792
842
793
func (h *Handle) RepoForkSync(w http.ResponseWriter, r *http.Request) {