1package xrpc
2
3import (
4 "encoding/json"
5 "fmt"
6 "net/http"
7 "net/url"
8
9 "tangled.sh/tangled.sh/core/knotserver/git"
10 "tangled.sh/tangled.sh/core/types"
11 xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
12)
13
14func (x *Xrpc) RepoCompare(w http.ResponseWriter, r *http.Request) {
15 repo := r.URL.Query().Get("repo")
16 repoPath, err := x.parseRepoParam(repo)
17 if err != nil {
18 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
19 return
20 }
21
22 rev1Param := r.URL.Query().Get("rev1")
23 if rev1Param == "" {
24 writeError(w, xrpcerr.NewXrpcError(
25 xrpcerr.WithTag("InvalidRequest"),
26 xrpcerr.WithMessage("missing rev1 parameter"),
27 ), http.StatusBadRequest)
28 return
29 }
30
31 rev2Param := r.URL.Query().Get("rev2")
32 if rev2Param == "" {
33 writeError(w, xrpcerr.NewXrpcError(
34 xrpcerr.WithTag("InvalidRequest"),
35 xrpcerr.WithMessage("missing rev2 parameter"),
36 ), http.StatusBadRequest)
37 return
38 }
39
40 rev1, _ := url.PathUnescape(rev1Param)
41 rev2, _ := url.PathUnescape(rev2Param)
42
43 gr, err := git.PlainOpen(repoPath)
44 if err != nil {
45 writeError(w, xrpcerr.NewXrpcError(
46 xrpcerr.WithTag("RepoNotFound"),
47 xrpcerr.WithMessage("repository not found"),
48 ), http.StatusNotFound)
49 return
50 }
51
52 commit1, err := gr.ResolveRevision(rev1)
53 if err != nil {
54 x.Logger.Error("error resolving revision 1", "msg", err.Error())
55 writeError(w, xrpcerr.NewXrpcError(
56 xrpcerr.WithTag("RevisionNotFound"),
57 xrpcerr.WithMessage(fmt.Sprintf("error resolving revision %s", rev1)),
58 ), http.StatusBadRequest)
59 return
60 }
61
62 commit2, err := gr.ResolveRevision(rev2)
63 if err != nil {
64 x.Logger.Error("error resolving revision 2", "msg", err.Error())
65 writeError(w, xrpcerr.NewXrpcError(
66 xrpcerr.WithTag("RevisionNotFound"),
67 xrpcerr.WithMessage(fmt.Sprintf("error resolving revision %s", rev2)),
68 ), http.StatusBadRequest)
69 return
70 }
71
72 rawPatch, formatPatch, err := gr.FormatPatch(commit1, commit2)
73 if err != nil {
74 x.Logger.Error("error comparing revisions", "msg", err.Error())
75 writeError(w, xrpcerr.NewXrpcError(
76 xrpcerr.WithTag("CompareError"),
77 xrpcerr.WithMessage("error comparing revisions"),
78 ), http.StatusBadRequest)
79 return
80 }
81
82 resp := types.RepoFormatPatchResponse{
83 Rev1: commit1.Hash.String(),
84 Rev2: commit2.Hash.String(),
85 FormatPatch: formatPatch,
86 Patch: rawPatch,
87 }
88
89 w.Header().Set("Content-Type", "application/json")
90 if err := json.NewEncoder(w).Encode(resp); err != nil {
91 x.Logger.Error("failed to encode response", "error", err)
92 writeError(w, xrpcerr.NewXrpcError(
93 xrpcerr.WithTag("InternalServerError"),
94 xrpcerr.WithMessage("failed to encode response"),
95 ), http.StatusInternalServerError)
96 return
97 }
98}