1package xrpc
2
3import (
4 "context"
5 "encoding/json"
6 "math"
7 "net/http"
8 "net/url"
9 "time"
10
11 "tangled.sh/tangled.sh/core/api/tangled"
12 "tangled.sh/tangled.sh/core/knotserver/git"
13 xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
14)
15
16func (x *Xrpc) RepoLanguages(w http.ResponseWriter, r *http.Request) {
17 refParam := r.URL.Query().Get("ref")
18 if refParam == "" {
19 refParam = "HEAD" // default
20 }
21 ref, _ := url.PathUnescape(refParam)
22
23 repo := r.URL.Query().Get("repo")
24 repoPath, err := x.parseRepoParam(repo)
25 if err != nil {
26 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
27 return
28 }
29
30 gr, err := git.Open(repoPath, ref)
31 if err != nil {
32 x.Logger.Error("opening repo", "error", err.Error())
33 writeError(w, xrpcerr.NewXrpcError(
34 xrpcerr.WithTag("RefNotFound"),
35 xrpcerr.WithMessage("repository or ref not found"),
36 ), http.StatusNotFound)
37 return
38 }
39
40 ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second)
41 defer cancel()
42
43 sizes, err := gr.AnalyzeLanguages(ctx)
44 if err != nil {
45 x.Logger.Error("failed to analyze languages", "error", err.Error())
46 writeError(w, xrpcerr.NewXrpcError(
47 xrpcerr.WithTag("InvalidRequest"),
48 xrpcerr.WithMessage("failed to analyze repository languages"),
49 ), http.StatusNoContent)
50 return
51 }
52
53 var apiLanguages []*tangled.RepoLanguages_Language
54 var totalSize int64
55
56 for _, size := range sizes {
57 totalSize += size
58 }
59
60 for name, size := range sizes {
61 percentagef64 := float64(size) / float64(totalSize) * 100
62 percentage := math.Round(percentagef64)
63
64 lang := &tangled.RepoLanguages_Language{
65 Name: name,
66 Size: size,
67 Percentage: int64(percentage),
68 }
69
70 apiLanguages = append(apiLanguages, lang)
71 }
72
73 response := tangled.RepoLanguages_Output{
74 Ref: ref,
75 Languages: apiLanguages,
76 }
77
78 if totalSize > 0 {
79 response.TotalSize = &totalSize
80 totalFiles := int64(len(sizes))
81 response.TotalFiles = &totalFiles
82 }
83
84 w.Header().Set("Content-Type", "application/json")
85 if err := json.NewEncoder(w).Encode(response); err != nil {
86 x.Logger.Error("failed to encode response", "error", err)
87 writeError(w, xrpcerr.NewXrpcError(
88 xrpcerr.WithTag("InternalServerError"),
89 xrpcerr.WithMessage("failed to encode response"),
90 ), http.StatusInternalServerError)
91 return
92 }
93}