From 22e1f6f92f1d94d33ee53265376598201760e0ee Mon Sep 17 00:00:00 2001 From: Lewis Date: Wed, 13 May 2026 10:53:57 +0300 Subject: [PATCH] knotmirror: temp git xrpc to use repodid Lewis: May this revision serve well! --- api/tangled/repoblob.go | 2 +- api/tangled/tempanalyzeMerge.go | 2 +- api/tangled/tempgetArchive.go | 2 +- api/tangled/tempgetBlob.go | 2 +- api/tangled/tempgetBranch.go | 2 +- api/tangled/tempgetCommit.go | 2 +- api/tangled/tempgetDiff.go | 2 +- api/tangled/tempgetEntity.go | 2 +- api/tangled/tempgetHead.go | 2 +- api/tangled/tempgetTag.go | 2 +- api/tangled/tempgetTree.go | 2 +- api/tangled/templistBranches.go | 2 +- api/tangled/templistCommits.go | 2 +- api/tangled/templistLanguages.go | 2 +- api/tangled/templistTags.go | 2 +- appview/pulls/compose.go | 2 +- appview/pulls/resubmit_check_test.go | 166 ++++++++++++++++++++++++++ appview/pulls/single.go | 2 +- appview/repo/archive.go | 2 +- appview/repo/artifact.go | 2 +- appview/repo/blob.go | 4 +- appview/repo/branches.go | 2 +- appview/repo/compare.go | 4 +- appview/repo/feed.go | 4 +- appview/repo/index.go | 10 +- appview/repo/log.go | 6 +- appview/repo/settings.go | 2 +- appview/repo/tags.go | 6 +- appview/repo/tree.go | 2 +- knotmirror/git.go | 9 ++ knotmirror/tapclient.go | 10 ++ knotmirror/xrpc/git_get_archive.go | 6 +- knotmirror/xrpc/git_get_blob.go | 8 +- knotmirror/xrpc/git_get_branch.go | 8 +- knotmirror/xrpc/git_get_tag.go | 8 +- knotmirror/xrpc/git_get_tree.go | 8 +- knotmirror/xrpc/git_list_branches.go | 26 ++-- knotmirror/xrpc/git_list_commits.go | 8 +- knotmirror/xrpc/git_list_languages.go | 10 +- knotmirror/xrpc/git_list_tags.go | 8 +- knotmirror/xrpc/proxy.go | 77 +++++------- knotmirror/xrpc/repo_blob.go | 8 +- lexicons/git/temp/analyzeMerge.json | 4 +- lexicons/git/temp/getArchive.json | 4 +- lexicons/git/temp/getBlob.json | 4 +- lexicons/git/temp/getBranch.json | 4 +- lexicons/git/temp/getCommit.json | 4 +- lexicons/git/temp/getDiff.json | 4 +- lexicons/git/temp/getEntity.json | 4 +- lexicons/git/temp/getHead.json | 4 +- lexicons/git/temp/getTag.json | 4 +- lexicons/git/temp/getTree.json | 4 +- lexicons/git/temp/listBranches.json | 4 +- lexicons/git/temp/listCommits.json | 4 +- lexicons/git/temp/listLanguages.json | 4 +- lexicons/git/temp/listTags.json | 4 +- lexicons/repo/blob.json | 3 +- 57 files changed, 331 insertions(+), 166 deletions(-) create mode 100644 appview/pulls/resubmit_check_test.go diff --git a/api/tangled/repoblob.go b/api/tangled/repoblob.go index 30965ec6..3e5d6ee3 100644 --- a/api/tangled/repoblob.go +++ b/api/tangled/repoblob.go @@ -72,7 +72,7 @@ type RepoBlob_Submodule struct { // path: Path to the file within the repository // raw: Return raw file content instead of JSON response // ref: Git reference (branch, tag, or commit SHA) -// repo: Repository identifier in format 'did:plc:.../repoName' +// repo: DID of the repository func RepoBlob(ctx context.Context, c util.LexClient, path string, raw bool, ref string, repo string) (*RepoBlob_Output, error) { var out RepoBlob_Output diff --git a/api/tangled/tempanalyzeMerge.go b/api/tangled/tempanalyzeMerge.go index a63a4a80..e2089343 100644 --- a/api/tangled/tempanalyzeMerge.go +++ b/api/tangled/tempanalyzeMerge.go @@ -34,7 +34,7 @@ type GitTempAnalyzeMerge_Output struct { // // branch: Target branch to merge into // patch: Patch or pull request to check for merge conflicts -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempAnalyzeMerge(ctx context.Context, c util.LexClient, branch string, patch string, repo string) (*GitTempAnalyzeMerge_Output, error) { var out GitTempAnalyzeMerge_Output diff --git a/api/tangled/tempgetArchive.go b/api/tangled/tempgetArchive.go index 4b7e2701..fce25f1a 100644 --- a/api/tangled/tempgetArchive.go +++ b/api/tangled/tempgetArchive.go @@ -20,7 +20,7 @@ const ( // format: Archive format // prefix: Prefix for files in the archive // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetArchive(ctx context.Context, c util.LexClient, format string, prefix string, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetBlob.go b/api/tangled/tempgetBlob.go index f06db684..d6623e13 100644 --- a/api/tangled/tempgetBlob.go +++ b/api/tangled/tempgetBlob.go @@ -19,7 +19,7 @@ const ( // // path: Path within the repository tree // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetBlob(ctx context.Context, c util.LexClient, path string, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetBranch.go b/api/tangled/tempgetBranch.go index f68f335c..d0ad395c 100644 --- a/api/tangled/tempgetBranch.go +++ b/api/tangled/tempgetBranch.go @@ -30,7 +30,7 @@ type GitTempGetBranch_Output struct { // GitTempGetBranch calls the XRPC method "sh.tangled.git.temp.getBranch". // // name: Branch name to get information for -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetBranch(ctx context.Context, c util.LexClient, name string, repo string) (*GitTempGetBranch_Output, error) { var out GitTempGetBranch_Output diff --git a/api/tangled/tempgetCommit.go b/api/tangled/tempgetCommit.go index 0d9acce7..4965f3de 100644 --- a/api/tangled/tempgetCommit.go +++ b/api/tangled/tempgetCommit.go @@ -17,7 +17,7 @@ const ( // GitTempGetCommit calls the XRPC method "sh.tangled.git.temp.getCommit". // // ref: reference name to resolve -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetCommit(ctx context.Context, c util.LexClient, ref string, repo string) (*GitTempDefs_Commit, error) { var out GitTempDefs_Commit diff --git a/api/tangled/tempgetDiff.go b/api/tangled/tempgetDiff.go index 7c33553e..236d6cfd 100644 --- a/api/tangled/tempgetDiff.go +++ b/api/tangled/tempgetDiff.go @@ -17,7 +17,7 @@ const ( // GitTempGetDiff calls the XRPC method "sh.tangled.git.temp.getDiff". // -// repo: AT-URI of the repository +// repo: DID of the repository // rev1: First revision (commit, branch, or tag) // rev2: Second revision (commit, branch, or tag) func GitTempGetDiff(ctx context.Context, c util.LexClient, repo string, rev1 string, rev2 string) ([]byte, error) { diff --git a/api/tangled/tempgetEntity.go b/api/tangled/tempgetEntity.go index 1138646d..6cd88ba5 100644 --- a/api/tangled/tempgetEntity.go +++ b/api/tangled/tempgetEntity.go @@ -18,7 +18,7 @@ const ( // // path: path of the entity // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetEntity(ctx context.Context, c util.LexClient, path string, ref string, repo string) (*GitTempDefs_Blob, error) { var out GitTempDefs_Blob diff --git a/api/tangled/tempgetHead.go b/api/tangled/tempgetHead.go index 5b148065..c0928cfd 100644 --- a/api/tangled/tempgetHead.go +++ b/api/tangled/tempgetHead.go @@ -16,7 +16,7 @@ const ( // GitTempGetHead calls the XRPC method "sh.tangled.git.temp.getHead". // -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetHead(ctx context.Context, c util.LexClient, repo string) (*GitTempDefs_Branch, error) { var out GitTempDefs_Branch diff --git a/api/tangled/tempgetTag.go b/api/tangled/tempgetTag.go index 77b1444d..ac5d8689 100644 --- a/api/tangled/tempgetTag.go +++ b/api/tangled/tempgetTag.go @@ -17,7 +17,7 @@ const ( // GitTempGetTag calls the XRPC method "sh.tangled.git.temp.getTag". // -// repo: AT-URI of the repository +// repo: DID of the repository // tag: Name of tag, such as v1.3.0 func GitTempGetTag(ctx context.Context, c util.LexClient, repo string, tag string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/tempgetTree.go b/api/tangled/tempgetTree.go index 8b74c0f9..b86c3ee4 100644 --- a/api/tangled/tempgetTree.go +++ b/api/tangled/tempgetTree.go @@ -72,7 +72,7 @@ type GitTempGetTree_TreeEntry struct { // // path: Path within the repository tree // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempGetTree(ctx context.Context, c util.LexClient, path string, ref string, repo string) (*GitTempGetTree_Output, error) { var out GitTempGetTree_Output diff --git a/api/tangled/templistBranches.go b/api/tangled/templistBranches.go index a879e7a4..6ac3e401 100644 --- a/api/tangled/templistBranches.go +++ b/api/tangled/templistBranches.go @@ -19,7 +19,7 @@ const ( // // cursor: Pagination cursor // limit: Maximum number of branches to return -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListBranches(ctx context.Context, c util.LexClient, cursor string, limit int64, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/templistCommits.go b/api/tangled/templistCommits.go index 10c07b6c..120d6452 100644 --- a/api/tangled/templistCommits.go +++ b/api/tangled/templistCommits.go @@ -20,7 +20,7 @@ const ( // cursor: Pagination cursor (commit SHA) // limit: Maximum number of commits to return // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListCommits(ctx context.Context, c util.LexClient, cursor string, limit int64, ref string, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/api/tangled/templistLanguages.go b/api/tangled/templistLanguages.go index a32f236f..0fa7396f 100644 --- a/api/tangled/templistLanguages.go +++ b/api/tangled/templistLanguages.go @@ -44,7 +44,7 @@ type GitTempListLanguages_Output struct { // GitTempListLanguages calls the XRPC method "sh.tangled.git.temp.listLanguages". // // ref: Git reference (branch, tag, or commit SHA) -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListLanguages(ctx context.Context, c util.LexClient, ref string, repo string) (*GitTempListLanguages_Output, error) { var out GitTempListLanguages_Output diff --git a/api/tangled/templistTags.go b/api/tangled/templistTags.go index 8a976db6..61158439 100644 --- a/api/tangled/templistTags.go +++ b/api/tangled/templistTags.go @@ -19,7 +19,7 @@ const ( // // cursor: Pagination cursor // limit: Maximum number of tags to return -// repo: AT-URI of the repository +// repo: DID of the repository func GitTempListTags(ctx context.Context, c util.LexClient, cursor string, limit int64, repo string) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/appview/pulls/compose.go b/appview/pulls/compose.go index 51fc61e9..c1362f63 100644 --- a/appview/pulls/compose.go +++ b/appview/pulls/compose.go @@ -334,7 +334,7 @@ func (s *Pulls) composeParams(r *http.Request, repo *models.Repo) (pages.RepoNew func (s *Pulls) listBranches(ctx context.Context, repo *models.Repo) ([]types.Branch, error) { xrpcc := &indigoxrpc.Client{Host: s.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { return nil, err } diff --git a/appview/pulls/resubmit_check_test.go b/appview/pulls/resubmit_check_test.go new file mode 100644 index 00000000..6dbb198d --- /dev/null +++ b/appview/pulls/resubmit_check_test.go @@ -0,0 +1,166 @@ +package pulls + +import ( + "context" + "encoding/json" + "io" + "log/slog" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/bluesky-social/indigo/atproto/syntax" + "tangled.org/core/api/tangled" + "tangled.org/core/appview/config" + "tangled.org/core/appview/models" + "tangled.org/core/appview/pages" +) + +const ( + resubmitTestOwnerDID = "did:plc:boltless" + resubmitTestRepoDID = "did:plc:akshay" + resubmitTestBranch = "feature" + resubmitTestSourceRev = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +) + +func newKnotmirrorStub(t *testing.T, hash string) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/xrpc/"+tangled.GitTempGetBranchNSID { + t.Errorf("unexpected path %q", r.URL.Path) + http.Error(w, "wrong path", http.StatusNotFound) + return + } + repoQuery := r.URL.Query().Get("repo") + if _, err := syntax.ParseDID(repoQuery); err != nil { + t.Errorf("repo param %q is not a DID: %v", repoQuery, err) + http.Error(w, "repo must be a DID", http.StatusBadRequest) + return + } + if got := r.URL.Query().Get("name"); got != resubmitTestBranch { + t.Errorf("name param = %q, want %q", got, resubmitTestBranch) + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(tangled.GitTempGetBranch_Output{ + Name: resubmitTestBranch, + Hash: hash, + When: time.Now().UTC().Format(time.RFC3339), + }) + })) +} + +func newPullsFromKnotURL(url string) *Pulls { + return &Pulls{ + logger: slog.New(slog.NewTextHandler(io.Discard, nil)), + config: &config.Config{ + KnotMirror: config.KnotMirrorConfig{Url: url}, + }, + } +} + +func newForkPull(state models.PullState) (*models.Pull, *models.Repo, models.Stack) { + sourceRepoDid := syntax.DID(resubmitTestRepoDID) + pull := &models.Pull{ + State: state, + OwnerDid: resubmitTestOwnerDID, + TargetBranch: "main", + Submissions: []*models.PullSubmission{ + {SourceRev: resubmitTestSourceRev}, + }, + PullSource: &models.PullSource{ + Branch: resubmitTestBranch, + RepoDid: &sourceRepoDid, + }, + } + repo := &models.Repo{RepoDid: resubmitTestRepoDID} + stack := models.Stack{pull} + return pull, repo, stack +} + +func TestResubmitCheck_BranchAdvanced(t *testing.T) { + srv := newKnotmirrorStub(t, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + + got := s.resubmitCheck(req, repo, pull, stack) + if got != pages.ShouldResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldResubmit", got) + } +} + +func TestResubmitCheck_BranchUpToDate(t *testing.T) { + srv := newKnotmirrorStub(t, resubmitTestSourceRev) + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + + got := s.resubmitCheck(req, repo, pull, stack) + if got != pages.ShouldNotResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldNotResubmit", got) + } +} + +func TestResubmitCheck_MergedReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://unused") + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullMerged) + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown for merged pull", got) + } +} + +func TestResubmitCheck_PatchBasedReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://unused") + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, repo, stack := newForkPull(models.PullOpen) + pull.PullSource = nil + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown for patch-based pull", got) + } +} + +func TestResubmitCheck_KnotUnreachableReturnsUnknown(t *testing.T) { + s := newPullsFromKnotURL("http://127.0.0.1:1") + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + req := httptest.NewRequest(http.MethodGet, "/", nil).WithContext(ctx) + pull, repo, stack := newForkPull(models.PullOpen) + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.Unknown { + t.Errorf("resubmitCheck() = %v, want Unknown when knot unreachable", got) + } +} + +func TestResubmitCheck_NonForkUsesRepoDid(t *testing.T) { + const targetRepoDID = "did:plc:scallop" + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got := r.URL.Query().Get("repo"); got != targetRepoDID { + t.Errorf("repo param = %q, want %q for non-fork pull", got, targetRepoDID) + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(tangled.GitTempGetBranch_Output{ + Name: resubmitTestBranch, + Hash: resubmitTestSourceRev, + When: time.Now().UTC().Format(time.RFC3339), + }) + })) + defer srv.Close() + + s := newPullsFromKnotURL(srv.URL) + req := httptest.NewRequest(http.MethodGet, "/", nil) + pull, _, stack := newForkPull(models.PullOpen) + pull.PullSource.RepoDid = nil + repo := &models.Repo{RepoDid: targetRepoDID} + + if got := s.resubmitCheck(req, repo, pull, stack); got != pages.ShouldNotResubmit { + t.Errorf("resubmitCheck() = %v, want ShouldNotResubmit", got) + } +} diff --git a/appview/pulls/single.go b/appview/pulls/single.go index b26fdad4..e75e2143 100644 --- a/appview/pulls/single.go +++ b/appview/pulls/single.go @@ -350,7 +350,7 @@ func (s *Pulls) branchDeleteStatus(r *http.Request, repo *models.Repo, pull *mod } xrpcc := &indigoxrpc.Client{Host: s.config.KnotMirror.Url} - resp, err := tangled.GitTempGetBranch(r.Context(), xrpcc, branch, repo.RepoAt().String()) + resp, err := tangled.GitTempGetBranch(r.Context(), xrpcc, branch, repo.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { s.logger.Error("failed to get branch", "xrpcerr", xrpcerr, "err", err) return nil diff --git a/appview/repo/archive.go b/appview/repo/archive.go index 4b36f604..eadbe015 100644 --- a/appview/repo/archive.go +++ b/appview/repo/archive.go @@ -24,7 +24,7 @@ func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) { // build the xrpc url query := url.Values{} - query.Set("repo", f.RepoAt().String()) + query.Set("repo", f.RepoDid) query.Set("ref", ref) query.Set("format", "tar.gz") query.Set("prefix", r.URL.Query().Get("prefix")) diff --git a/appview/repo/artifact.go b/appview/repo/artifact.go index 4f29fa50..e3a5f0da 100644 --- a/appview/repo/artifact.go +++ b/appview/repo/artifact.go @@ -310,7 +310,7 @@ func (rp *Repo) resolveTag(ctx context.Context, f *models.Repo, tagParam string) xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, f.RepoDid) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tags", "xrpcerr", xrpcerr, "err", err) diff --git a/appview/repo/blob.go b/appview/repo/blob.go index 915fa06e..4c2e4999 100644 --- a/appview/repo/blob.go +++ b/appview/repo/blob.go @@ -52,7 +52,7 @@ func (rp *Repo) Blob(w http.ResponseWriter, r *http.Request) { filePath, _ = url.PathUnescape(filePath) xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoAt().String()) + resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.blob", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) @@ -272,7 +272,7 @@ func NewBlobView(resp *tangled.RepoBlob_Output, config *config.Config, repo *mod func generateBlobURL(config *config.Config, repo *models.Repo, ref, filePath string) string { query := url.Values{} - query.Set("repo", string(repo.RepoAt())) + query.Set("repo", repo.RepoDid) query.Set("ref", ref) query.Set("path", filePath) query.Set("raw", "true") diff --git a/appview/repo/branches.go b/appview/repo/branches.go index 65bd7e80..a3ccc10a 100644 --- a/appview/repo/branches.go +++ b/appview/repo/branches.go @@ -23,7 +23,7 @@ func (rp *Repo) Branches(w http.ResponseWriter, r *http.Request) { } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.branches", "err", err) rp.pages.Error503(w) diff --git a/appview/repo/compare.go b/appview/repo/compare.go index 0446e779..0e415538 100644 --- a/appview/repo/compare.go +++ b/appview/repo/compare.go @@ -32,7 +32,7 @@ func (rp *Repo) CompareNew(w http.ResponseWriter, r *http.Request) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.branches", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) @@ -69,7 +69,7 @@ func (rp *Repo) CompareNew(w http.ResponseWriter, r *http.Request) { head = queryHead } - tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tags", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/appview/repo/feed.go b/appview/repo/feed.go index 17ad09b9..d3644c8e 100644 --- a/appview/repo/feed.go +++ b/appview/repo/feed.go @@ -209,7 +209,7 @@ func (rp *Repo) createIssueItem(ctx context.Context, issue models.Issue, ownerSl func (rp *Repo) createCommitItems(ctx context.Context, repo *models.Repo, ownerSlashRepo string) ([]*feeds.Item, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 100, "", repo.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 100, "", repo.RepoDid) if err != nil { return nil, fmt.Errorf("failed to call XRPC repo.log: %w", err) } @@ -248,7 +248,7 @@ func (rp *Repo) createCommitItems(ctx context.Context, repo *models.Repo, ownerS func (rp *Repo) createTagItems(ctx context.Context, repo *models.Repo, ownerSlashRepo string) ([]*feeds.Item, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - tagBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 100, repo.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 100, repo.RepoDid) if err != nil { return nil, fmt.Errorf("failed to call XRPC repo.tags: %w", err) } diff --git a/appview/repo/index.go b/appview/repo/index.go index d8a5515b..f6782c26 100644 --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -171,7 +171,7 @@ func (rp *Repo) getLanguageInfo( Host: rp.config.KnotMirror.Url, Client: http.DefaultClient, } - ls, err := tangled.GitTempListLanguages(ctx, xrpcc, currentRef, repo.RepoAt().String()) + ls, err := tangled.GitTempListLanguages(ctx, xrpcc, currentRef, repo.RepoDid) if err != nil { return nil, fmt.Errorf("calling knotmirror git.listLanguages: %w", err) } @@ -254,7 +254,7 @@ func containsOtherLanguage(langs []models.RepoLanguage) bool { func (rp *Repo) buildIndexResponse(ctx context.Context, repo *models.Repo, ref string) (*types.RepoIndexResponse, error) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - branchesBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoAt().String()) + branchesBytes, err := tangled.GitTempListBranches(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { return nil, fmt.Errorf("calling knotmirror git.listBranches: %w", err) } @@ -296,7 +296,7 @@ func (rp *Repo) buildIndexResponse(ctx context.Context, repo *models.Repo, ref s // tags wg.Go(func() { - tagsBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, repo.RepoAt().String()) + tagsBytes, err := tangled.GitTempListTags(ctx, xrpcc, "", 0, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.ListTags: %w", err)) return @@ -309,7 +309,7 @@ func (rp *Repo) buildIndexResponse(ctx context.Context, repo *models.Repo, ref s // tree/files wg.Go(func() { - resp, err := tangled.GitTempGetTree(ctx, xrpcc, "", ref, repo.RepoAt().String()) + resp, err := tangled.GitTempGetTree(ctx, xrpcc, "", ref, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.GetTree: %w", err)) return @@ -319,7 +319,7 @@ func (rp *Repo) buildIndexResponse(ctx context.Context, repo *models.Repo, ref s // commits wg.Go(func() { - logBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 50, ref, repo.RepoAt().String()) + logBytes, err := tangled.GitTempListCommits(ctx, xrpcc, "", 50, ref, repo.RepoDid) if err != nil { errs = errors.Join(errs, fmt.Errorf("failed to call git.ListCommits: %w", err)) return diff --git a/appview/repo/log.go b/appview/repo/log.go index 3e11e3ae..85659c03 100644 --- a/appview/repo/log.go +++ b/appview/repo/log.go @@ -111,7 +111,7 @@ func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { cursor = strconv.Itoa(offset) } - xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListCommits(r.Context(), xrpcc, cursor, limit, ref, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.log", "err", err) rp.pages.Error503(w) @@ -125,7 +125,7 @@ func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { return } - tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + tagBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.tags", "err", err) rp.pages.Error503(w) @@ -146,7 +146,7 @@ func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { } } - branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + branchBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.branches", "err", err) rp.pages.Error503(w) diff --git a/appview/repo/settings.go b/appview/repo/settings.go index 6cacb958..e0516f9a 100644 --- a/appview/repo/settings.go +++ b/appview/repo/settings.go @@ -381,7 +381,7 @@ func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListBranches(r.Context(), xrpcc, "", 0, f.RepoDid) var result types.RepoBranchesResponse if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC git.listBranches", "xrpcerr", xrpcerr, "err", err) diff --git a/appview/repo/tags.go b/appview/repo/tags.go index a7d4d7e4..c1fc970c 100644 --- a/appview/repo/tags.go +++ b/appview/repo/tags.go @@ -28,7 +28,7 @@ func (rp *Repo) Tags(w http.ResponseWriter, r *http.Request) { return } xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoAt().String()) + xrpcBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 0, f.RepoDid) if err != nil { l.Error("failed to call XRPC repo.tags", "err", err) rp.pages.Error503(w) @@ -86,13 +86,13 @@ func (rp *Repo) Tag(w http.ResponseWriter, r *http.Request) { xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcBytes, err := tangled.GitTempGetTag(r.Context(), xrpcc, f.RepoAt().String(), tag) + xrpcBytes, err := tangled.GitTempGetTag(r.Context(), xrpcc, f.RepoDid, tag) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { // if we don't match an existing tag, and the tag we're trying // to match is "latest", resolve to the most recent tag l.Info("failed to call XRPC git.getTag", "xrpcerr", xrpcerr, "err", err, "tag", tag) if tag == "latest" { - tagsBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 1, f.RepoAt().String()) + tagsBytes, err := tangled.GitTempListTags(r.Context(), xrpcc, "", 1, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC git.ListTags for latest", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/appview/repo/tree.go b/appview/repo/tree.go index 23355c3d..d4f80f2f 100644 --- a/appview/repo/tree.go +++ b/appview/repo/tree.go @@ -35,7 +35,7 @@ func (rp *Repo) Tree(w http.ResponseWriter, r *http.Request) { treePath = strings.TrimSuffix(treePath, "/") xrpcc := &indigoxrpc.Client{Host: rp.config.KnotMirror.Url} - xrpcResp, err := tangled.GitTempGetTree(r.Context(), xrpcc, treePath, ref, f.RepoAt().String()) + xrpcResp, err := tangled.GitTempGetTree(r.Context(), xrpcc, treePath, ref, f.RepoDid) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tree", "xrpcerr", xrpcerr, "err", err) rp.pages.Error503(w) diff --git a/knotmirror/git.go b/knotmirror/git.go index b6081be8..e87ae956 100644 --- a/knotmirror/git.go +++ b/knotmirror/git.go @@ -25,6 +25,7 @@ type GitMirrorManager interface { Fetch(ctx context.Context, repo *models.Repo) error // Sync mirrors the repository. It will clone the repository if repository doesn't exist. Sync(ctx context.Context, repo *models.Repo) error + Delete(repo *models.Repo) error } type CliGitMirrorManager struct { @@ -116,6 +117,10 @@ func (c *CliGitMirrorManager) Sync(ctx context.Context, repo *models.Repo) error return nil } +func (c *CliGitMirrorManager) Delete(repo *models.Repo) error { + return os.RemoveAll(c.makeRepoPath(repo)) +} + var ( ErrDNSFailure = errors.New("git: knot: dns failure (could not resolve host)") ErrCertExpired = errors.New("git: knot: certificate has expired") @@ -251,6 +256,10 @@ func (c *GoGitMirrorManager) Sync(ctx context.Context, repo *models.Repo) error return nil } +func (c *GoGitMirrorManager) Delete(repo *models.Repo) error { + return os.RemoveAll(c.makeRepoPath(repo)) +} + func makeRepoRemoteUrl(knot, repoIdentifier string, knotUseSSL bool) (string, error) { if !strings.Contains(knot, "://") { if knotUseSSL { diff --git a/knotmirror/tapclient.go b/knotmirror/tapclient.go index 190d08b2..6a1fcf4f 100644 --- a/knotmirror/tapclient.go +++ b/knotmirror/tapclient.go @@ -133,6 +133,16 @@ func (t *Tap) processRepo(ctx context.Context, evt *tapc.RecordEventData) error } case tapc.RecordDeleteAction: + aturi := syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", evt.Did, tangled.RepoNSID, evt.Rkey)) + repo, err := db.GetRepoByAtUri(ctx, t.db, aturi) + if err != nil { + return fmt.Errorf("looking up repo before delete: %w", err) + } + if repo != nil { + if err := t.gitm.Delete(repo); err != nil { + return fmt.Errorf("removing mirror dir: %w", err) + } + } if err := db.DeleteRepo(ctx, t.db, evt.Did, evt.Rkey); err != nil { return fmt.Errorf("deleting repo from db: %w", err) } diff --git a/knotmirror/xrpc/git_get_archive.go b/knotmirror/xrpc/git_get_archive.go index 9541c19d..f9c8ad2f 100644 --- a/knotmirror/xrpc/git_get_archive.go +++ b/knotmirror/xrpc/git_get_archive.go @@ -23,8 +23,8 @@ func (x *Xrpc) GetArchive(w http.ResponseWriter, r *http.Request) { prefix = r.URL.Query().Get("prefix") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -61,7 +61,7 @@ func (x *Xrpc) GetArchive(w http.ResponseWriter, r *http.Request) { } repoName, err := func() (string, error) { - r, err := db.GetRepoByAtUri(ctx, x.db, repo) + r, err := db.GetRepoByRepoDid(ctx, x.db, repo) if err != nil { return "", err } diff --git a/knotmirror/xrpc/git_get_blob.go b/knotmirror/xrpc/git_get_blob.go index 400d34c3..66bd8ac0 100644 --- a/knotmirror/xrpc/git_get_blob.go +++ b/knotmirror/xrpc/git_get_blob.go @@ -24,8 +24,8 @@ func (x *Xrpc) GetBlob(w http.ResponseWriter, r *http.Request) { path = r.URL.Query().Get("path") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -111,10 +111,10 @@ func (x *Xrpc) GetBlob(w http.ResponseWriter, r *http.Request) { w.Write(contents) } -func (x *Xrpc) getFile(ctx context.Context, repo syntax.ATURI, ref, path string) (*object.File, error) { +func (x *Xrpc) getFile(ctx context.Context, repo syntax.DID, ref, path string) (*object.File, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_get_branch.go b/knotmirror/xrpc/git_get_branch.go index 2a30bd76..01f5110e 100644 --- a/knotmirror/xrpc/git_get_branch.go +++ b/knotmirror/xrpc/git_get_branch.go @@ -21,8 +21,8 @@ func (x *Xrpc) GetBranch(w http.ResponseWriter, r *http.Request) { nameQuery = r.URL.Query().Get("name") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -45,10 +45,10 @@ func (x *Xrpc) GetBranch(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getBranch(ctx context.Context, repo syntax.ATURI, branchName string) (*tangled.GitTempGetBranch_Output, error) { +func (x *Xrpc) getBranch(ctx context.Context, repo syntax.DID, branchName string) (*tangled.GitTempGetBranch_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/git_get_tag.go b/knotmirror/xrpc/git_get_tag.go index 698a1f8c..edd97a21 100644 --- a/knotmirror/xrpc/git_get_tag.go +++ b/knotmirror/xrpc/git_get_tag.go @@ -19,8 +19,8 @@ func (x *Xrpc) GetTag(w http.ResponseWriter, r *http.Request) { tagName = r.URL.Query().Get("tag") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -42,10 +42,10 @@ func (x *Xrpc) GetTag(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getTag(ctx context.Context, repo syntax.ATURI, tagName string) (*types.RepoTagResponse, error) { +func (x *Xrpc) getTag(ctx context.Context, repo syntax.DID, tagName string) (*types.RepoTagResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/git_get_tree.go b/knotmirror/xrpc/git_get_tree.go index a8f6e85e..3897976f 100644 --- a/knotmirror/xrpc/git_get_tree.go +++ b/knotmirror/xrpc/git_get_tree.go @@ -26,8 +26,8 @@ func (x *Xrpc) GetTree(w http.ResponseWriter, r *http.Request) { l := x.logger.With("method", "git.getTree", "repo", repoQuery, "ref", ref) l.Debug("request") - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -47,10 +47,10 @@ func (x *Xrpc) GetTree(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) getTree(ctx context.Context, repo syntax.ATURI, ref, path string) (*tangled.GitTempGetTree_Output, error) { +func (x *Xrpc) getTree(ctx context.Context, repo syntax.DID, ref, path string) (*tangled.GitTempGetTree_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_branches.go b/knotmirror/xrpc/git_list_branches.go index 28158911..48cb367b 100644 --- a/knotmirror/xrpc/git_list_branches.go +++ b/knotmirror/xrpc/git_list_branches.go @@ -4,12 +4,12 @@ import ( "context" "fmt" "net/http" + "os" "path/filepath" "strconv" "github.com/bluesky-social/indigo/atproto/atclient" "github.com/bluesky-social/indigo/atproto/syntax" - "tangled.org/core/knotmirror/db" "tangled.org/core/knotserver/git" "tangled.org/core/types" ) @@ -21,8 +21,8 @@ func (x *Xrpc) ListBranches(w http.ResponseWriter, r *http.Request) { cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -57,10 +57,10 @@ func (x *Xrpc) ListBranches(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listBranches(ctx context.Context, repo syntax.ATURI, limit int, cursor int64) (*types.RepoBranchesResponse, error) { +func (x *Xrpc) listBranches(ctx context.Context, repo syntax.DID, limit int, cursor int64) (*types.RepoBranchesResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.PlainOpen(repoPath) @@ -82,16 +82,10 @@ func (x *Xrpc) listBranches(ctx context.Context, repo syntax.ATURI, limit int, c }, nil } -func (x *Xrpc) makeRepoPath(ctx context.Context, repo syntax.ATURI) (string, error) { - r, err := db.GetRepoByAtUri(ctx, x.db, repo) - if err != nil { - return "", fmt.Errorf("looking up repo: %w", err) - } - if r == nil { - return "", fmt.Errorf("repo not found: %s", repo) - } - if r.RepoDid == "" { - return "", fmt.Errorf("repo missing repo_did: %s", repo) +func (x *Xrpc) makeRepoPath(ctx context.Context, repoDid syntax.DID) (string, error) { + path := filepath.Join(x.cfg.GitRepoBasePath, repoDid.String()) + if _, err := os.Stat(path); err != nil { + return "", fmt.Errorf("repo %s not mirrored locally: %w", repoDid, err) } - return filepath.Join(x.cfg.GitRepoBasePath, r.RepoDid.String()), nil + return path, nil } diff --git a/knotmirror/xrpc/git_list_commits.go b/knotmirror/xrpc/git_list_commits.go index 87a9d7c7..3ced1040 100644 --- a/knotmirror/xrpc/git_list_commits.go +++ b/knotmirror/xrpc/git_list_commits.go @@ -20,8 +20,8 @@ func (x *Xrpc) ListCommits(w http.ResponseWriter, r *http.Request) { cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -56,10 +56,10 @@ func (x *Xrpc) ListCommits(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listCommits(ctx context.Context, repo syntax.ATURI, ref string, limit int, cursor int64) (*types.RepoLogResponse, error) { +func (x *Xrpc) listCommits(ctx context.Context, repo syntax.DID, ref string, limit int, cursor int64) (*types.RepoLogResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_languages.go b/knotmirror/xrpc/git_list_languages.go index db7470aa..fe1ce4e5 100644 --- a/knotmirror/xrpc/git_list_languages.go +++ b/knotmirror/xrpc/git_list_languages.go @@ -28,9 +28,9 @@ func (x *Xrpc) ListLanguages(w http.ResponseWriter, r *http.Request) { l := x.logger.With("method", "git.listLanguages", "repo", repoQuery, "ref", ref) l.Debug("request") - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { - l.Error("invalid repo at-uri", "err", err) + repo, err := syntax.ParseDID(repoQuery) + if err != nil { + l.Error("invalid repo did", "err", err) writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -64,10 +64,10 @@ func (x *Xrpc) ListLanguages(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listLanguages(ctx context.Context, repo syntax.ATURI, ref string) (*tangled.GitTempListLanguages_Output, error) { +func (x *Xrpc) listLanguages(ctx context.Context, repo syntax.DID, ref string) (*tangled.GitTempListLanguages_Output, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/knotmirror/xrpc/git_list_tags.go b/knotmirror/xrpc/git_list_tags.go index 8661e4b5..c0b94d75 100644 --- a/knotmirror/xrpc/git_list_tags.go +++ b/knotmirror/xrpc/git_list_tags.go @@ -21,8 +21,8 @@ func (x *Xrpc) ListTags(w http.ResponseWriter, r *http.Request) { cursorQuery = r.URL.Query().Get("cursor") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -57,10 +57,10 @@ func (x *Xrpc) ListTags(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, out) } -func (x *Xrpc) listTags(ctx context.Context, repo syntax.ATURI, limit int, cursor int64) (*types.RepoTagsResponse, error) { +func (x *Xrpc) listTags(ctx context.Context, repo syntax.DID, limit int, cursor int64) (*types.RepoTagsResponse, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("failed to resolve repo at-uri: %w", err) + return nil, fmt.Errorf("failed to resolve repo did: %w", err) } gr, err := git.PlainOpen(repoPath) diff --git a/knotmirror/xrpc/proxy.go b/knotmirror/xrpc/proxy.go index 565569e7..533dccd4 100644 --- a/knotmirror/xrpc/proxy.go +++ b/knotmirror/xrpc/proxy.go @@ -9,7 +9,6 @@ import ( "net/url" "strings" - "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/atproto/syntax" indigoxrpc "github.com/bluesky-social/indigo/xrpc" "tangled.org/core/api/tangled" @@ -70,9 +69,8 @@ func validateKnotURL(raw string) (string, error) { return strings.TrimRight(u.String(), "/"), nil } -func (x *Xrpc) resolveKnot(ctx context.Context, repoAt syntax.ATURI) (*knotInfo, error) { - repo, err := db.GetRepoByAtUri(ctx, x.db, repoAt) - if err == nil && repo != nil { +func (x *Xrpc) resolveKnot(ctx context.Context, repoDid syntax.DID) (*knotInfo, error) { + if repo, err := db.GetRepoByRepoDid(ctx, x.db, repoDid); err == nil && repo != nil { knotURL := repo.KnotDomain if !strings.Contains(repo.KnotDomain, "://") { if host, _ := db.GetHost(ctx, x.db, repo.KnotDomain); host != nil { @@ -93,73 +91,60 @@ func (x *Xrpc) resolveKnot(ctx context.Context, repoAt syntax.ATURI) (*knotInfo, return &knotInfo{baseURL: knotURL, repoIdentifier: repo.RepoIdentifier()}, nil } - owner, err := x.resolver.ResolveIdent(ctx, repoAt.Authority().String()) + ident, err := x.resolver.ResolveIdent(ctx, repoDid.String()) if err != nil { - return nil, fmt.Errorf("resolving repo owner: %w", err) + return nil, fmt.Errorf("resolving repoDid %s: %w", repoDid, err) } - - xrpcc := indigoxrpc.Client{Host: owner.PDSEndpoint()} - out, err := atproto.RepoGetRecord(ctx, &xrpcc, "", tangled.RepoNSID, repoAt.Authority().String(), repoAt.RecordKey().String()) + knotURL, err := validateKnotURL(ident.GetServiceEndpoint("atproto_pds")) if err != nil { - return nil, fmt.Errorf("fetching repo record from PDS: %w", err) + return nil, fmt.Errorf("repoDid %s: %w", repoDid, err) } - record := out.Value.Val.(*tangled.Repo) - if record.RepoDid == nil || *record.RepoDid == "" { - return nil, fmt.Errorf("repo record has no repo_did") + xrpcc := &indigoxrpc.Client{Host: knotURL, Client: x.httpClient} + out, err := tangled.RepoDescribeRepo(ctx, xrpcc, repoDid.String()) + if err != nil { + x.logger.Warn("describeRepo failed; serving without metadata upsert", "knot", knotURL, "repo", repoDid, "err", err) + return &knotInfo{baseURL: knotURL, repoIdentifier: repoDid.String()}, nil } - knotURL := record.Knot - if !strings.Contains(record.Knot, "://") { - if host, _ := db.GetHost(ctx, x.db, record.Knot); host != nil { - knotURL = host.URL() - } else { - x.logger.Warn("repo is from unknown knot") - if x.cfg.KnotUseSSL { - knotURL = "https://" + knotURL - } else { - knotURL = "http://" + knotURL - } - } + if out.RepoDid != repoDid.String() { + return nil, fmt.Errorf("knot %s returned mismatched repoDid: got %q, want %q", knotURL, out.RepoDid, repoDid) + } + ownerDid, err := syntax.ParseDID(out.OwnerDid) + if err != nil { + return nil, fmt.Errorf("describeRepo on %s returned invalid ownerDid %q: %w", knotURL, out.OwnerDid, err) + } + rkey, err := syntax.ParseRecordKey(out.Rkey) + if err != nil { + return nil, fmt.Errorf("describeRepo on %s returned invalid rkey %q: %w", knotURL, out.Rkey, err) } - rkey := repoAt.RecordKey().String() - repoDid := syntax.DID(*record.RepoDid) go func() { - bgCtx := context.Background() pending := &models.Repo{ - Did: owner.DID, - Rkey: repoAt.RecordKey(), - Cid: (*syntax.CID)(out.Cid), - Name: rkey, + Did: ownerDid, + Rkey: rkey, + Name: string(rkey), KnotDomain: knotURL, RepoDid: repoDid, State: models.RepoStatePending, } - if upsertErr := db.UpsertRepo(bgCtx, x.db, pending); upsertErr != nil { - x.logger.Error("failed to upsert repo after proxy resolution", "err", upsertErr) + if err := db.UpsertRepo(context.Background(), x.db, pending); err != nil { + x.logger.Error("failed to upsert repo after directory resolution", "err", err) } }() - knotURL, err = validateKnotURL(knotURL) - if err != nil { - return nil, err - } - return &knotInfo{ - baseURL: knotURL, - repoIdentifier: repoDid.String(), - }, nil + return &knotInfo{baseURL: knotURL, repoIdentifier: repoDid.String()}, nil } -func (x *Xrpc) proxyToKnot(w http.ResponseWriter, r *http.Request, repoAt syntax.ATURI) bool { +func (x *Xrpc) proxyToKnot(w http.ResponseWriter, r *http.Request, repoDid syntax.DID) bool { mirrorNSID := strings.TrimPrefix(r.URL.Path, "/xrpc/") knotNSID, ok := mirrorToKnotNSID[mirrorNSID] if !ok { return false } - knot, err := x.resolveKnot(r.Context(), repoAt) + knot, err := x.resolveKnot(r.Context(), repoDid) if err != nil { - x.logger.Warn("proxy: failed to resolve knot", "repo", repoAt, "err", err) + x.logger.Warn("proxy: failed to resolve knot", "repo", repoDid, "err", err) return false } @@ -197,6 +182,6 @@ func (x *Xrpc) proxyToKnot(w http.ResponseWriter, r *http.Request, repoAt syntax x.logger.Warn("proxy: response copy interrupted", "target", target, "err", err) } - x.logger.Info("proxy: served from knot", "repo", repoAt, "knot", knot.baseURL, "status", resp.StatusCode) + x.logger.Info("proxy: served from knot", "repo", repoDid, "knot", knot.baseURL, "status", resp.StatusCode) return true } diff --git a/knotmirror/xrpc/repo_blob.go b/knotmirror/xrpc/repo_blob.go index df8a354c..71d763b1 100644 --- a/knotmirror/xrpc/repo_blob.go +++ b/knotmirror/xrpc/repo_blob.go @@ -24,8 +24,8 @@ func (x *Xrpc) RepoBlob(w http.ResponseWriter, r *http.Request) { path = r.URL.Query().Get("path") ) - repo, err := syntax.ParseATURI(repoQuery) - if err != nil || repo.RecordKey() == "" { + repo, err := syntax.ParseDID(repoQuery) + if err != nil { writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) return } @@ -155,10 +155,10 @@ func (x *Xrpc) RepoBlob(w http.ResponseWriter, r *http.Request) { writeJson(w, http.StatusOK, response) } -func (x *Xrpc) getRepo(ctx context.Context, repo syntax.ATURI, ref string) (*git.GitRepo, error) { +func (x *Xrpc) getRepo(ctx context.Context, repo syntax.DID, ref string) (*git.GitRepo, error) { repoPath, err := x.makeRepoPath(ctx, repo) if err != nil { - return nil, fmt.Errorf("resolving repo at-uri: %w", err) + return nil, fmt.Errorf("resolving repo did: %w", err) } gr, err := git.Open(repoPath, ref) diff --git a/lexicons/git/temp/analyzeMerge.json b/lexicons/git/temp/analyzeMerge.json index b84f31d7..c8072bd4 100644 --- a/lexicons/git/temp/analyzeMerge.json +++ b/lexicons/git/temp/analyzeMerge.json @@ -11,8 +11,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "patch": { "type": "string", diff --git a/lexicons/git/temp/getArchive.json b/lexicons/git/temp/getArchive.json index 215c15c2..3e8c6da4 100644 --- a/lexicons/git/temp/getArchive.json +++ b/lexicons/git/temp/getArchive.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getBlob.json b/lexicons/git/temp/getBlob.json index 9f431306..f65c4aeb 100644 --- a/lexicons/git/temp/getBlob.json +++ b/lexicons/git/temp/getBlob.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getBranch.json b/lexicons/git/temp/getBranch.json index 24c65286..5dd00eb5 100644 --- a/lexicons/git/temp/getBranch.json +++ b/lexicons/git/temp/getBranch.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "name": { "type": "string", diff --git a/lexicons/git/temp/getCommit.json b/lexicons/git/temp/getCommit.json index b70d9964..b1ff03b2 100644 --- a/lexicons/git/temp/getCommit.json +++ b/lexicons/git/temp/getCommit.json @@ -11,8 +11,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getDiff.json b/lexicons/git/temp/getDiff.json index e31137e3..d8fb288b 100644 --- a/lexicons/git/temp/getDiff.json +++ b/lexicons/git/temp/getDiff.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "rev1": { "type": "string", diff --git a/lexicons/git/temp/getEntity.json b/lexicons/git/temp/getEntity.json index 31a48fa9..76633535 100644 --- a/lexicons/git/temp/getEntity.json +++ b/lexicons/git/temp/getEntity.json @@ -11,8 +11,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/getHead.json b/lexicons/git/temp/getHead.json index e054f9c5..21c72988 100644 --- a/lexicons/git/temp/getHead.json +++ b/lexicons/git/temp/getHead.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" } } }, diff --git a/lexicons/git/temp/getTag.json b/lexicons/git/temp/getTag.json index e71f7916..622318d3 100644 --- a/lexicons/git/temp/getTag.json +++ b/lexicons/git/temp/getTag.json @@ -13,8 +13,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "tag": { "type": "string", diff --git a/lexicons/git/temp/getTree.json b/lexicons/git/temp/getTree.json index ecd12f7a..4dd8506d 100644 --- a/lexicons/git/temp/getTree.json +++ b/lexicons/git/temp/getTree.json @@ -13,8 +13,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listBranches.json b/lexicons/git/temp/listBranches.json index f3b22c80..97bb3506 100644 --- a/lexicons/git/temp/listBranches.json +++ b/lexicons/git/temp/listBranches.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "limit": { "type": "integer", diff --git a/lexicons/git/temp/listCommits.json b/lexicons/git/temp/listCommits.json index 01ac0ca3..4f2ec72d 100644 --- a/lexicons/git/temp/listCommits.json +++ b/lexicons/git/temp/listCommits.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listLanguages.json b/lexicons/git/temp/listLanguages.json index 405af2ee..ec3c8566 100644 --- a/lexicons/git/temp/listLanguages.json +++ b/lexicons/git/temp/listLanguages.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", diff --git a/lexicons/git/temp/listTags.json b/lexicons/git/temp/listTags.json index 2f18fe07..0590b182 100644 --- a/lexicons/git/temp/listTags.json +++ b/lexicons/git/temp/listTags.json @@ -10,8 +10,8 @@ "properties": { "repo": { "type": "string", - "format": "at-uri", - "description": "AT-URI of the repository" + "format": "did", + "description": "DID of the repository" }, "limit": { "type": "integer", diff --git a/lexicons/repo/blob.json b/lexicons/repo/blob.json index 4a6012f6..cf6541a5 100644 --- a/lexicons/repo/blob.json +++ b/lexicons/repo/blob.json @@ -14,7 +14,8 @@ "properties": { "repo": { "type": "string", - "description": "Repository identifier in format 'did:plc:.../repoName'" + "format": "did", + "description": "DID of the repository" }, "ref": { "type": "string", -- 2.51.2