This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knotmirror / xrpc / git_get_entry.go
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}