A vibe coded tangled fork which supports pijul.
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}