forked from tangled.org/core
this repo has no description
at master 2.7 kB view raw
1package xrpc 2 3import ( 4 "net/http" 5 "path/filepath" 6 "time" 7 "unicode/utf8" 8 9 "tangled.org/core/api/tangled" 10 "tangled.org/core/appview/pages/markup" 11 "tangled.org/core/knotserver/git" 12 xrpcerr "tangled.org/core/xrpc/errors" 13) 14 15func (x *Xrpc) RepoTree(w http.ResponseWriter, r *http.Request) { 16 ctx := r.Context() 17 18 repo := r.URL.Query().Get("repo") 19 repoPath, err := x.parseRepoParam(repo) 20 if err != nil { 21 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest) 22 return 23 } 24 25 ref := r.URL.Query().Get("ref") 26 // ref can be empty (git.Open handles this) 27 28 path := r.URL.Query().Get("path") 29 // path can be empty (defaults to root) 30 31 gr, err := git.Open(repoPath, ref) 32 if err != nil { 33 x.Logger.Error("failed to open git repository", "error", err, "path", repoPath, "ref", ref) 34 writeError(w, xrpcerr.RefNotFoundError, http.StatusNotFound) 35 return 36 } 37 38 files, err := gr.FileTree(ctx, path) 39 if err != nil { 40 x.Logger.Error("failed to get file tree", "error", err, "path", path) 41 writeError(w, xrpcerr.NewXrpcError( 42 xrpcerr.WithTag("PathNotFound"), 43 xrpcerr.WithMessage("failed to read repository tree"), 44 ), http.StatusNotFound) 45 return 46 } 47 48 // if any of these files are a readme candidate, pass along its blob contents too 49 var readmeFileName string 50 var readmeContents string 51 for _, file := range files { 52 if markup.IsReadmeFile(file.Name) { 53 contents, err := gr.RawContent(filepath.Join(path, file.Name)) 54 if err != nil { 55 x.Logger.Error("failed to read contents of file", "path", path, "file", file.Name) 56 } 57 58 if utf8.Valid(contents) { 59 readmeFileName = file.Name 60 readmeContents = string(contents) 61 break 62 } 63 } 64 } 65 66 // convert NiceTree -> tangled.RepoTree_TreeEntry 67 treeEntries := make([]*tangled.RepoTree_TreeEntry, len(files)) 68 for i, file := range files { 69 entry := &tangled.RepoTree_TreeEntry{ 70 Name: file.Name, 71 Mode: file.Mode, 72 Size: file.Size, 73 Is_file: file.IsFile, 74 Is_subtree: file.IsSubtree, 75 } 76 77 if file.LastCommit != nil { 78 entry.Last_commit = &tangled.RepoTree_LastCommit{ 79 Hash: file.LastCommit.Hash.String(), 80 Message: file.LastCommit.Message, 81 When: file.LastCommit.When.Format(time.RFC3339), 82 } 83 } 84 85 treeEntries[i] = entry 86 } 87 88 var parentPtr *string 89 if path != "" { 90 parentPtr = &path 91 } 92 93 var dotdotPtr *string 94 if path != "" { 95 dotdot := filepath.Dir(path) 96 if dotdot != "." { 97 dotdotPtr = &dotdot 98 } 99 } 100 101 response := tangled.RepoTree_Output{ 102 Ref: ref, 103 Parent: parentPtr, 104 Dotdot: dotdotPtr, 105 Files: treeEntries, 106 Readme: &tangled.RepoTree_Readme{ 107 Filename: readmeFileName, 108 Contents: readmeContents, 109 }, 110 } 111 112 writeJson(w, response) 113}