A vibe coded tangled fork which supports pijul.
at 1237bf9f58e4ba5d13d5437f2f82a2078572e229 95 lines 2.6 kB view raw
1package xrpc 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "strconv" 8 9 "github.com/bluesky-social/indigo/atproto/atclient" 10 "github.com/bluesky-social/indigo/atproto/syntax" 11 "tangled.org/core/knotserver/git" 12 "tangled.org/core/types" 13) 14 15func (x *Xrpc) ListCommits(w http.ResponseWriter, r *http.Request) { 16 var ( 17 repoQuery = r.URL.Query().Get("repo") 18 ref = r.URL.Query().Get("ref") // ref can be empty (git.Open handles this) 19 limitQuery = r.URL.Query().Get("limit") 20 cursorQuery = r.URL.Query().Get("cursor") 21 ) 22 23 repo, err := syntax.ParseATURI(repoQuery) 24 if err != nil || repo.RecordKey() == "" { 25 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) 26 return 27 } 28 29 limit := 50 30 if limitQuery != "" { 31 limit, err = strconv.Atoi(limitQuery) 32 if err != nil || limit < 1 || limit > 1000 { 33 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("limit parameter invalid: %s", limitQuery)}) 34 return 35 } 36 } 37 38 var cursor int64 39 if cursorQuery != "" { 40 cursor, err = strconv.ParseInt(cursorQuery, 10, 64) 41 if err != nil || cursor < 0 { 42 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("cursor parameter invalid: %s", cursorQuery)}) 43 return 44 } 45 } 46 47 l := x.logger.With("repo", repo, "ref", ref) 48 49 out, err := x.listCommits(r.Context(), repo, ref, limit, cursor) 50 if err != nil { 51 // TODO: better error return 52 l.Error("failed to list commits", "err", err) 53 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to list commits"}) 54 return 55 } 56 writeJson(w, http.StatusOK, out) 57} 58 59func (x *Xrpc) listCommits(ctx context.Context, repo syntax.ATURI, ref string, limit int, cursor int64) (*types.RepoLogResponse, error) { 60 repoPath, err := x.makeRepoPath(ctx, repo) 61 if err != nil { 62 return nil, fmt.Errorf("resolving repo at-uri: %w", err) 63 } 64 65 gr, err := git.Open(repoPath, ref) 66 if err != nil { 67 return nil, fmt.Errorf("opening git repo: %w", err) 68 } 69 70 offset := int(cursor) 71 72 commits, err := gr.Commits(offset, limit) 73 if err != nil { 74 return nil, fmt.Errorf("listing git commits: %w", err) 75 } 76 77 tcommits := make([]types.Commit, len(commits)) 78 for i, c := range commits { 79 tcommits[i].FromGoGitCommit(c) 80 } 81 82 total, err := gr.TotalCommits() 83 if err != nil { 84 return nil, fmt.Errorf("counting total commits: %w", err) 85 } 86 87 return &types.RepoLogResponse{ 88 Commits: tcommits, 89 Ref: ref, 90 Page: (offset / limit) + 1, 91 PerPage: limit, 92 Total: total, 93 Log: true, 94 }, nil 95}