1package xrpc
2
3import (
4 "net/http"
5 "path/filepath"
6 "time"
7
8 "tangled.org/core/api/tangled"
9 "tangled.org/core/knotserver/git"
10 xrpcerr "tangled.org/core/xrpc/errors"
11)
12
13func (x *Xrpc) RepoTree(w http.ResponseWriter, r *http.Request) {
14 ctx := r.Context()
15
16 repo := r.URL.Query().Get("repo")
17 repoPath, err := x.parseRepoParam(repo)
18 if err != nil {
19 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
20 return
21 }
22
23 ref := r.URL.Query().Get("ref")
24 // ref can be empty (git.Open handles this)
25
26 path := r.URL.Query().Get("path")
27 // path can be empty (defaults to root)
28
29 gr, err := git.Open(repoPath, ref)
30 if err != nil {
31 x.Logger.Error("failed to open git repository", "error", err, "path", repoPath, "ref", ref)
32 writeError(w, xrpcerr.RefNotFoundError, http.StatusNotFound)
33 return
34 }
35
36 files, err := gr.FileTree(ctx, path)
37 if err != nil {
38 x.Logger.Error("failed to get file tree", "error", err, "path", path)
39 writeError(w, xrpcerr.NewXrpcError(
40 xrpcerr.WithTag("PathNotFound"),
41 xrpcerr.WithMessage("failed to read repository tree"),
42 ), http.StatusNotFound)
43 return
44 }
45
46 // convert NiceTree -> tangled.RepoTree_TreeEntry
47 treeEntries := make([]*tangled.RepoTree_TreeEntry, len(files))
48 for i, file := range files {
49 entry := &tangled.RepoTree_TreeEntry{
50 Name: file.Name,
51 Mode: file.Mode,
52 Size: file.Size,
53 Is_file: file.IsFile,
54 Is_subtree: file.IsSubtree,
55 }
56
57 if file.LastCommit != nil {
58 entry.Last_commit = &tangled.RepoTree_LastCommit{
59 Hash: file.LastCommit.Hash.String(),
60 Message: file.LastCommit.Message,
61 When: file.LastCommit.When.Format(time.RFC3339),
62 }
63 }
64
65 treeEntries[i] = entry
66 }
67
68 var parentPtr *string
69 if path != "" {
70 parentPtr = &path
71 }
72
73 var dotdotPtr *string
74 if path != "" {
75 dotdot := filepath.Dir(path)
76 if dotdot != "." {
77 dotdotPtr = &dotdot
78 }
79 }
80
81 response := tangled.RepoTree_Output{
82 Ref: ref,
83 Parent: parentPtr,
84 Dotdot: dotdotPtr,
85 Files: treeEntries,
86 }
87
88 writeJson(w, response)
89}