A vibe coded tangled fork which supports pijul.
at sl/knotmirror 212 lines 5.5 kB view raw
1package repo 2 3import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/url" 8 "strconv" 9 10 "tangled.org/core/api/tangled" 11 "tangled.org/core/appview/commitverify" 12 "tangled.org/core/appview/db" 13 "tangled.org/core/appview/models" 14 "tangled.org/core/appview/pages" 15 xrpcclient "tangled.org/core/appview/xrpcclient" 16 "tangled.org/core/types" 17 18 indigoxrpc "github.com/bluesky-social/indigo/xrpc" 19 "github.com/go-chi/chi/v5" 20 "github.com/go-git/go-git/v5/plumbing" 21) 22 23func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { 24 l := rp.logger.With("handler", "RepoLog") 25 26 f, err := rp.repoResolver.Resolve(r) 27 if err != nil { 28 l.Error("failed to fully resolve repo", "err", err) 29 return 30 } 31 32 page := 1 33 if r.URL.Query().Get("page") != "" { 34 page, err = strconv.Atoi(r.URL.Query().Get("page")) 35 if err != nil { 36 page = 1 37 } 38 } 39 40 ref := chi.URLParam(r, "ref") 41 ref, _ = url.PathUnescape(ref) 42 43 xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} 44 45 limit := int64(60) 46 cursor := "" 47 if page > 1 { 48 // Convert page number to cursor (offset) 49 offset := (page - 1) * int(limit) 50 cursor = strconv.Itoa(offset) 51 } 52 53 xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoAt().String()) 54 if err != nil { 55 l.Error("failed to call XRPC repo.log", "err", err) 56 rp.pages.Error503(w) 57 return 58 } 59 60 var xrpcResp types.RepoLogResponse 61 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil { 62 l.Error("failed to decode XRPC response", "err", err) 63 rp.pages.Error503(w) 64 return 65 } 66 67 tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) 68 if err != nil { 69 l.Error("failed to call XRPC repo.tags", "err", err) 70 rp.pages.Error503(w) 71 return 72 } 73 74 tagMap := make(map[string][]string) 75 if tagBytes != nil { 76 var tagResp types.RepoTagsResponse 77 if err := json.Unmarshal(tagBytes, &tagResp); err == nil { 78 for _, tag := range tagResp.Tags { 79 hash := tag.Hash 80 if tag.Tag != nil { 81 hash = tag.Tag.Target.String() 82 } 83 tagMap[hash] = append(tagMap[hash], tag.Name) 84 } 85 } 86 } 87 88 branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) 89 if err != nil { 90 l.Error("failed to call XRPC repo.branches", "err", err) 91 rp.pages.Error503(w) 92 return 93 } 94 95 if branchBytes != nil { 96 var branchResp types.RepoBranchesResponse 97 if err := json.Unmarshal(branchBytes, &branchResp); err == nil { 98 for _, branch := range branchResp.Branches { 99 tagMap[branch.Hash] = append(tagMap[branch.Hash], branch.Name) 100 } 101 } 102 } 103 104 user := rp.oauth.GetMultiAccountUser(r) 105 106 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true) 107 if err != nil { 108 l.Error("failed to fetch email to did mapping", "err", err) 109 } 110 111 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, xrpcResp.Commits) 112 if err != nil { 113 l.Error("failed to GetVerifiedObjectCommits", "err", err) 114 } 115 116 var shas []string 117 for _, c := range xrpcResp.Commits { 118 shas = append(shas, c.Hash.String()) 119 } 120 pipelines, err := getPipelineStatuses(rp.db, f, shas) 121 if err != nil { 122 l.Error("failed to getPipelineStatuses", "err", err) 123 // non-fatal 124 } 125 126 rp.pages.RepoLog(w, pages.RepoLogParams{ 127 LoggedInUser: user, 128 TagMap: tagMap, 129 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 130 RepoLogResponse: xrpcResp, 131 EmailToDid: emailToDidMap, 132 VerifiedCommits: vc, 133 Pipelines: pipelines, 134 }) 135} 136 137func (rp *Repo) Commit(w http.ResponseWriter, r *http.Request) { 138 l := rp.logger.With("handler", "RepoCommit") 139 140 f, err := rp.repoResolver.Resolve(r) 141 if err != nil { 142 l.Error("failed to fully resolve repo", "err", err) 143 return 144 } 145 ref := chi.URLParam(r, "ref") 146 ref, _ = url.PathUnescape(ref) 147 148 var diffOpts types.DiffOpts 149 if d := r.URL.Query().Get("diff"); d == "split" { 150 diffOpts.Split = true 151 } 152 153 if !plumbing.IsHash(ref) { 154 rp.pages.Error404(w) 155 return 156 } 157 158 scheme := "http" 159 if !rp.config.Core.Dev { 160 scheme = "https" 161 } 162 host := fmt.Sprintf("%s://%s", scheme, f.Knot) 163 xrpcc := &indigoxrpc.Client{ 164 Host: host, 165 } 166 167 repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 168 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) 169 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 170 l.Error("failed to call XRPC repo.diff", "err", xrpcerr) 171 rp.pages.Error503(w) 172 return 173 } 174 175 var result types.RepoCommitResponse 176 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 177 l.Error("failed to decode XRPC response", "err", err) 178 rp.pages.Error503(w) 179 return 180 } 181 182 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true) 183 if err != nil { 184 l.Error("failed to get email to did mapping", "err", err) 185 } 186 187 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.Commit{result.Diff.Commit}) 188 if err != nil { 189 l.Error("failed to GetVerifiedCommits", "err", err) 190 } 191 192 user := rp.oauth.GetMultiAccountUser(r) 193 pipelines, err := getPipelineStatuses(rp.db, f, []string{result.Diff.Commit.This}) 194 if err != nil { 195 l.Error("failed to getPipelineStatuses", "err", err) 196 // non-fatal 197 } 198 var pipeline *models.Pipeline 199 if p, ok := pipelines[result.Diff.Commit.This]; ok { 200 pipeline = &p 201 } 202 203 rp.pages.RepoCommit(w, pages.RepoCommitParams{ 204 LoggedInUser: user, 205 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 206 RepoCommitResponse: result, 207 EmailToDid: emailToDidMap, 208 VerifiedCommit: vc, 209 Pipeline: pipeline, 210 DiffOpts: diffOpts, 211 }) 212}