forked from tangled.org/core
this repo has no description

appview: rework RepoLanguages

- move endpoint on knot to /{did}/{name}/languages
- remove buggy percentage calculation
- fix endpoint to work on empty repos
- allowing calling endpoint with empty ref

Changed files
+59 -84
appview
knotclient
pages
state
knotserver
types
+17 -13
appview/knotclient/signer.go
···
return s.client.Do(req)
}
-
func (s *SignedClient) RepoLanguages(ownerDid, source, name, branch string) (*types.RepoLanguageResponse, error) {
+
func (s *SignedClient) RepoLanguages(ownerDid, repoName, ref string) (*types.RepoLanguageResponse, error) {
const (
Method = "GET"
)
-
endpoint := fmt.Sprintf("/repo/languages/%s", url.PathEscape(branch))
+
endpoint := fmt.Sprintf("/%s/%s/languages/%s", ownerDid, repoName, url.PathEscape(ref))
-
body, _ := json.Marshal(map[string]any{
-
"did": ownerDid,
-
"source": source,
-
"name": name,
-
})
-
-
req, err := s.newRequest(Method, endpoint, body)
+
req, err := s.newRequest(Method, endpoint, nil)
if err != nil {
return nil, err
}
···
return nil, err
}
-
var languagePercentages types.RepoLanguageResponse
-
if err := json.NewDecoder(resp.Body).Decode(&languagePercentages); err != nil {
-
log.Printf("failed to decode fork status: %s", err)
+
var result types.RepoLanguageResponse
+
if resp.StatusCode != http.StatusOK {
+
log.Println("failed to calculate languages", resp.Status)
+
return &types.RepoLanguageResponse{}, nil
+
}
+
+
body, err := io.ReadAll(resp.Body)
+
if err != nil {
return nil, err
}
-
return &languagePercentages, nil
+
err = json.Unmarshal(body, &result)
+
if err != nil {
+
return nil, err
+
}
+
+
return &result, nil
}
func (s *SignedClient) RepoForkAheadBehind(ownerDid, source, name, branch, hiddenRef string) (*http.Response, error) {
+12 -12
appview/pages/pages.go
···
}
type RepoIndexParams struct {
-
LoggedInUser *oauth.User
-
RepoInfo repoinfo.RepoInfo
-
Active string
-
TagMap map[string][]string
-
CommitsTrunc []*object.Commit
-
TagsTrunc []*types.TagReference
-
BranchesTrunc []types.Branch
-
ForkInfo *types.ForkInfo
+
LoggedInUser *oauth.User
+
RepoInfo repoinfo.RepoInfo
+
Active string
+
TagMap map[string][]string
+
CommitsTrunc []*object.Commit
+
TagsTrunc []*types.TagReference
+
BranchesTrunc []types.Branch
+
ForkInfo *types.ForkInfo
+
HTMLReadme template.HTML
+
Raw bool
+
EmailToDidOrHandle map[string]string
+
Languages *types.RepoLanguageResponse
types.RepoIndexResponse
-
HTMLReadme template.HTML
-
Raw bool
-
EmailToDidOrHandle map[string]string
-
LanguagePercentages map[string]float64
}
func (p *Pages) RepoIndexPage(w io.Writer, params RepoIndexParams) error {
+13 -14
appview/state/repo.go
···
var forkInfo *types.ForkInfo
if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
-
forkInfo, err = getForkInfo(repoInfo, s, f, w, user, signedClient)
+
forkInfo, err = getForkInfo(repoInfo, s, f, user, signedClient)
if err != nil {
log.Printf("Failed to fetch fork information: %v", err)
return
}
}
-
repoLanguages, err := signedClient.RepoLanguages(user.Did, string(f.RepoAt), repoInfo.Name, f.Ref)
+
repoLanguages, err := signedClient.RepoLanguages(f.OwnerDid(), f.RepoName, ref)
if err != nil {
log.Printf("failed to compute language percentages: %s", err)
-
return
+
// non-fatal
}
s.pages.RepoIndexPage(w, pages.RepoIndexParams{
-
LoggedInUser: user,
-
RepoInfo: repoInfo,
-
TagMap: tagMap,
-
RepoIndexResponse: result,
-
CommitsTrunc: commitsTrunc,
-
TagsTrunc: tagsTrunc,
-
ForkInfo: forkInfo,
-
BranchesTrunc: branchesTrunc,
-
EmailToDidOrHandle: EmailToDidOrHandle(s, emails),
-
LanguagePercentages: repoLanguages.Languages,
+
LoggedInUser: user,
+
RepoInfo: repoInfo,
+
TagMap: tagMap,
+
RepoIndexResponse: result,
+
CommitsTrunc: commitsTrunc,
+
TagsTrunc: tagsTrunc,
+
ForkInfo: forkInfo,
+
BranchesTrunc: branchesTrunc,
+
EmailToDidOrHandle: EmailToDidOrHandle(s, emails),
+
Languages: repoLanguages,
})
return
}
···
repoInfo repoinfo.RepoInfo,
s *State,
f *FullyResolvedRepo,
-
w http.ResponseWriter,
user *oauth.User,
signedClient *knotclient.SignedClient,
) (*types.ForkInfo, error) {
+6 -1
knotserver/handler.go
···
r.Post("/add", h.AddRepoCollaborator)
})
+
r.Route("/languages", func(r chi.Router) {
+
r.With(h.VerifySignature)
+
r.Get("/", h.RepoLanguages)
+
r.Get("/{ref}", h.RepoLanguages)
+
})
+
r.Get("/", h.RepoIndex)
r.Get("/info/refs", h.InfoRefs)
r.Post("/git-upload-pack", h.UploadPack)
···
r.Route("/repo", func(r chi.Router) {
r.Use(h.VerifySignature)
r.Put("/new", h.NewRepo)
-
r.Get("/languages/{branch}", h.RepoLanguages)
r.Delete("/", h.RemoveRepo)
r.Route("/fork", func(r chi.Router) {
r.Post("/", h.RepoFork)
+10 -43
knotserver/routes.go
···
}
func (h *Handle) RepoLanguages(w http.ResponseWriter, r *http.Request) {
-
l := h.l.With("handler", "RepoForkSync")
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
+
ref := chi.URLParam(r, "ref")
+
ref, _ = url.PathUnescape(ref)
-
data := struct {
-
Did string `json:"did"`
-
Source string `json:"source"`
-
Name string `json:"name,omitempty"`
-
}{}
+
l := h.l.With("handler", "RepoLanguages")
-
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
-
writeError(w, "invalid request body", http.StatusBadRequest)
-
return
-
}
-
-
did := data.Did
-
source := data.Source
-
-
if did == "" || source == "" {
-
l.Error("invalid request body, empty did or name")
-
w.WriteHeader(http.StatusBadRequest)
-
return
-
}
-
-
var name string
-
if data.Name != "" {
-
name = data.Name
-
} else {
-
name = filepath.Base(source)
-
}
-
-
branch := chi.URLParam(r, "branch")
-
branch, _ = url.PathUnescape(branch)
-
-
relativeRepoPath := filepath.Join(did, name)
-
repoPath, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, relativeRepoPath)
-
-
gr, err := git.Open(repoPath, branch)
+
gr, err := git.Open(path, ref)
if err != nil {
-
log.Println(err)
+
l.Error("opening repo", "error", err.Error())
notFound(w)
return
}
languageFileCount := make(map[string]int)
-
languagePercentage := make(map[string]float64)
err = recurseEntireTree(gr, func(absPath string) {
lang, safe := enry.GetLanguageByExtension(absPath)
···
}
}, "")
if err != nil {
-
log.Println(err)
+
l.Error("failed to recurse file tree", "error", err.Error())
writeError(w, err.Error(), http.StatusNoContent)
return
}
-
for path, fileCount := range languageFileCount {
-
percentage := float64(fileCount) / float64(len(languageFileCount)) * 100.0
-
languagePercentage[path] = percentage
-
}
+
resp := types.RepoLanguageResponse{Languages: languageFileCount}
-
w.Header().Set("Content-Type", "application/json")
-
json.NewEncoder(w).Encode(types.RepoLanguageResponse{Languages: languagePercentage})
+
writeJSON(w, resp)
+
return
}
func recurseEntireTree(git *git.GitRepo, callback func(absPath string), filePath string) error {
+1 -1
types/repo.go
···
type RepoLanguageResponse struct {
// Language: Percentage
-
Languages map[string]float64 `json:"languages"`
+
Languages map[string]int `json:"languages"`
}