This repository has no description
3.9 kB
133 lines
1package xrpc
2
3import (
4 "cmp"
5 "errors"
6 "fmt"
7 "net/http"
8 "time"
9
10 "github.com/bluesky-social/indigo/atproto/atclient"
11 "github.com/bluesky-social/indigo/atproto/syntax"
12 "github.com/go-git/go-git/v5/plumbing/filemode"
13 "tangled.org/core/api/tangled"
14 "tangled.org/core/knotmirror/xrpc/gitea"
15)
16
17func (x *Xrpc) GetEntry(w http.ResponseWriter, r *http.Request) {
18 var (
19 repoQuery = r.URL.Query().Get("repo")
20 ref = cmp.Or(r.URL.Query().Get("ref"), "HEAD")
21 path = r.URL.Query().Get("path")
22 )
23
24 repo, err := syntax.ParseDID(repoQuery)
25 if err != nil {
26 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)})
27 return
28 }
29
30 if path == "" {
31 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: "missing path parameter"})
32 return
33 }
34
35 l := x.logger.With("method", "git.getEntry", "repo", repo, "ref", ref, "path", path)
36 l.Debug("request")
37
38 ctx := r.Context()
39
40 repoPath, err := x.makeRepoPath(ctx, repo)
41 if err != nil {
42 writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "RepoNotFound", Message: fmt.Sprintf("unknown repository: %q", repo)})
43 return
44 }
45
46 // resolve ref
47 commit, err := gitea.GetCommit(ctx, repoPath, ref)
48 if err != nil {
49 writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "RefNotFound", Message: fmt.Sprintf("unknown ref: %q", ref)})
50 return
51 }
52 ref = commit.Hash.String()
53
54 entry, err := gitea.GetEntryFromCommit(ctx, repoPath, commit, path)
55 if err != nil {
56 writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "EntryNotFound", Message: fmt.Sprintf("entry %q not found", path)})
57 return
58 }
59 var size int64
60 switch entry.Mode {
61 case filemode.Empty, filemode.Dir, filemode.Submodule:
62 // no-op
63 default:
64 size, err = gitea.GetBlobSize(ctx, repoPath, entry.Hash)
65 if err != nil {
66 l.Error("failed to read blob size", "err", err)
67 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to read blob size"})
68 return
69 }
70 }
71
72 var outLastCommit *tangled.GitTempDefs_Commit
73 var outSubmodule *tangled.GitTempDefs_Submodule
74
75 lastCommit, err := gitea.GetCommitByPathWithID(ctx, commit.Hash, repoPath, path)
76 if err != nil {
77 l.Error("failed to find last commit", "err", err, "repoPath", repoPath)
78 } else {
79 outLastCommit = &tangled.GitTempDefs_Commit{
80 Hash: refString(lastCommit.Hash.String()),
81 Tree: refString(lastCommit.TreeHash.String()),
82 Author: &tangled.GitTempDefs_Signature{
83 Name: lastCommit.Author.Name,
84 Email: lastCommit.Author.Email,
85 When: lastCommit.Author.When.Format(time.RFC3339),
86 },
87 Committer: &tangled.GitTempDefs_Signature{
88 Name: lastCommit.Committer.Name,
89 Email: lastCommit.Committer.Email,
90 When: lastCommit.Committer.When.Format(time.RFC3339),
91 },
92 Message: lastCommit.Message,
93 }
94 }
95
96 if entry.Mode == filemode.Submodule {
97 modules, err := gitea.GetSubmodules(ctx, repoPath, ref)
98 if err != nil && !(errors.Is(err, gitea.ErrMissingGitModules) || errors.Is(err, gitea.ErrInvalidGitModules)) {
99 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to read .gitmodules"})
100 return
101 }
102
103 if modules != nil {
104 for _, submodule := range modules.Submodules {
105 if submodule.Path == path {
106 outSubmodule = &tangled.GitTempDefs_Submodule{
107 Name: submodule.Name,
108 Url: submodule.URL,
109 Branch: refOptionalString(submodule.Branch),
110 }
111 break
112 }
113 }
114 }
115 }
116
117 writeJson(w, http.StatusOK, tangled.GitTempGetEntry_Output{
118 Name: entry.Name,
119 Mode: entry.Mode.String(),
120 Oid: entry.Hash.String(),
121 Size: size,
122 LastCommit: outLastCommit,
123 Submodule: outSubmodule,
124 })
125}
126
127func refString(s string) *string { return &s }
128func refOptionalString(s string) *string {
129 if s == "" {
130 return nil
131 }
132 return &s
133}