package handler import ( "encoding/json" "fmt" "net/http" "os/exec" "path" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "tangled.org/core/api/tangled" "tangled.org/core/knot2/config" "tangled.org/core/log" xrpcerr "tangled.org/core/xrpc/errors" ) func XrpcGitKeepCommit(cfg *config.Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() l := log.FromContext(ctx).With("handler", "XrpcGitKeepCommit") // TODO: get session did actorDid := syntax.DID("") var input tangled.GitKeepCommit_Input if err := json.NewDecoder(r.Body).Decode(&input); err != nil { l.Error("failed to decode body", "err", err) panic("unimplemented") } repoAt, err := syntax.ParseATURI(input.Repo) if err != nil { l.Error("failed to decode body", "err", err) panic("unimplemented") } repoPath := repoPathFromAtUri(cfg, repoAt) // ensure repo exist (if not, clone it) repo, err := git.PlainOpen(repoPath) if err != nil { // TODO: clone the ref from source repo if repo doesn't exist in this knot yet l.Info("repo missing in knot", "err", err) panic("unimplemented") } commitId, err := repo.ResolveRevision(plumbing.Revision(input.Ref)) if err != nil { l.Error("failed to resolve revision", "ref", input.Ref, "err", err) panic("unimplemented") } // set keep-ref for given commit refspec := fmt.Sprintf("refs/knot/%s/keep/%s", actorDid, commitId) updateRefCmd := exec.Command("git", "-C", repoPath, "update-ref", refspec, commitId.String()) if err := updateRefCmd.Run(); err != nil { writeError(w, xrpcerr.GenericError(err), http.StatusBadRequest) return } output := tangled.GitKeepCommit_Output{ CommitId: commitId.String(), } w.WriteHeader(http.StatusOK) writeJson(w, output) } } func repoPathFromAtUri(cfg *config.Config, repoAt syntax.ATURI) string { return path.Join(cfg.RepoDir, repoAt.Authority().String(), repoAt.RecordKey().String()) } func writeError(w http.ResponseWriter, e xrpcerr.XrpcError, status int) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(e) } func writeJson(w http.ResponseWriter, response any) { w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(response); err != nil { writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError) return } }