forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

lexicons,knotserver: remove `sh.tangled.repo.archive`

Xrpc is not a good way to implement this as Xrpc clients usually strips
out the response http headers.
The archive should be implemented in raw http endpoint instead like git
https endpoints

Signed-off-by: Seongmin Lee <git@boltless.me>

boltless.me 1a5864d9 89c69cc1

verified
Changed files
-178
api
tangled
knotserver
lexicons
-41
api/tangled/repoarchive.go
···
-
// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
-
-
package tangled
-
-
// schema: sh.tangled.repo.archive
-
-
import (
-
"bytes"
-
"context"
-
-
"github.com/bluesky-social/indigo/lex/util"
-
)
-
-
const (
-
RepoArchiveNSID = "sh.tangled.repo.archive"
-
)
-
-
// RepoArchive calls the XRPC method "sh.tangled.repo.archive".
-
//
-
// format: Archive format
-
// prefix: Prefix for files in the archive
-
// ref: Git reference (branch, tag, or commit SHA)
-
// repo: Repository identifier in format 'did:plc:.../repoName'
-
func RepoArchive(ctx context.Context, c util.LexClient, format string, prefix string, ref string, repo string) ([]byte, error) {
-
buf := new(bytes.Buffer)
-
-
params := map[string]interface{}{}
-
if format != "" {
-
params["format"] = format
-
}
-
if prefix != "" {
-
params["prefix"] = prefix
-
}
-
params["ref"] = ref
-
params["repo"] = repo
-
if err := c.LexDo(ctx, util.Query, "", "sh.tangled.repo.archive", params, nil, buf); err != nil {
-
return nil, err
-
}
-
-
return buf.Bytes(), nil
-
}
-81
knotserver/xrpc/repo_archive.go
···
-
package xrpc
-
-
import (
-
"compress/gzip"
-
"fmt"
-
"net/http"
-
"strings"
-
-
"github.com/go-git/go-git/v5/plumbing"
-
-
"tangled.org/core/knotserver/git"
-
xrpcerr "tangled.org/core/xrpc/errors"
-
)
-
-
func (x *Xrpc) RepoArchive(w http.ResponseWriter, r *http.Request) {
-
repo := r.URL.Query().Get("repo")
-
repoPath, err := x.parseRepoParam(repo)
-
if err != nil {
-
writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
-
return
-
}
-
-
ref := r.URL.Query().Get("ref")
-
// ref can be empty (git.Open handles this)
-
-
format := r.URL.Query().Get("format")
-
if format == "" {
-
format = "tar.gz" // default
-
}
-
-
prefix := r.URL.Query().Get("prefix")
-
-
if format != "tar.gz" {
-
writeError(w, xrpcerr.NewXrpcError(
-
xrpcerr.WithTag("InvalidRequest"),
-
xrpcerr.WithMessage("only tar.gz format is supported"),
-
), http.StatusBadRequest)
-
return
-
}
-
-
gr, err := git.Open(repoPath, ref)
-
if err != nil {
-
writeError(w, xrpcerr.RefNotFoundError, http.StatusNotFound)
-
return
-
}
-
-
repoParts := strings.Split(repo, "/")
-
repoName := repoParts[len(repoParts)-1]
-
-
safeRefFilename := strings.ReplaceAll(plumbing.ReferenceName(ref).Short(), "/", "-")
-
-
var archivePrefix string
-
if prefix != "" {
-
archivePrefix = prefix
-
} else {
-
archivePrefix = fmt.Sprintf("%s-%s", repoName, safeRefFilename)
-
}
-
-
filename := fmt.Sprintf("%s-%s.tar.gz", repoName, safeRefFilename)
-
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
-
w.Header().Set("Content-Type", "application/gzip")
-
-
gw := gzip.NewWriter(w)
-
defer gw.Close()
-
-
err = gr.WriteTar(gw, archivePrefix)
-
if err != nil {
-
// once we start writing to the body we can't report error anymore
-
// so we are only left with logging the error
-
x.Logger.Error("writing tar file", "error", err.Error())
-
return
-
}
-
-
err = gw.Flush()
-
if err != nil {
-
// once we start writing to the body we can't report error anymore
-
// so we are only left with logging the error
-
x.Logger.Error("flushing", "error", err.Error())
-
return
-
}
-
}
-1
knotserver/xrpc/xrpc.go
···
r.Get("/"+tangled.RepoCompareNSID, x.RepoCompare)
r.Get("/"+tangled.RepoGetDefaultBranchNSID, x.RepoGetDefaultBranch)
r.Get("/"+tangled.RepoBranchNSID, x.RepoBranch)
-
r.Get("/"+tangled.RepoArchiveNSID, x.RepoArchive)
r.Get("/"+tangled.RepoLanguagesNSID, x.RepoLanguages)
// knot query endpoints (no auth required)
-55
lexicons/repo/archive.json
···
-
{
-
"lexicon": 1,
-
"id": "sh.tangled.repo.archive",
-
"defs": {
-
"main": {
-
"type": "query",
-
"parameters": {
-
"type": "params",
-
"required": ["repo", "ref"],
-
"properties": {
-
"repo": {
-
"type": "string",
-
"description": "Repository identifier in format 'did:plc:.../repoName'"
-
},
-
"ref": {
-
"type": "string",
-
"description": "Git reference (branch, tag, or commit SHA)"
-
},
-
"format": {
-
"type": "string",
-
"description": "Archive format",
-
"enum": ["tar", "zip", "tar.gz", "tar.bz2", "tar.xz"],
-
"default": "tar.gz"
-
},
-
"prefix": {
-
"type": "string",
-
"description": "Prefix for files in the archive"
-
}
-
}
-
},
-
"output": {
-
"encoding": "*/*",
-
"description": "Binary archive data"
-
},
-
"errors": [
-
{
-
"name": "RepoNotFound",
-
"description": "Repository not found or access denied"
-
},
-
{
-
"name": "RefNotFound",
-
"description": "Git reference not found"
-
},
-
{
-
"name": "InvalidRequest",
-
"description": "Invalid request parameters"
-
},
-
{
-
"name": "ArchiveError",
-
"description": "Failed to create archive"
-
}
-
]
-
}
-
}
-
}