this repo has no description
1package xrpc
2
3import (
4 "compress/gzip"
5 "fmt"
6 "net/http"
7 "strings"
8
9 "github.com/go-git/go-git/v5/plumbing"
10
11 "tangled.sh/tangled.sh/core/knotserver/git"
12 xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
13)
14
15func (x *Xrpc) RepoArchive(w http.ResponseWriter, r *http.Request) {
16 repo := r.URL.Query().Get("repo")
17 repoPath, err := x.parseRepoParam(repo)
18 if err != nil {
19 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
20 return
21 }
22
23 ref := r.URL.Query().Get("ref")
24 // ref can be empty (git.Open handles this)
25
26 format := r.URL.Query().Get("format")
27 if format == "" {
28 format = "tar.gz" // default
29 }
30
31 prefix := r.URL.Query().Get("prefix")
32
33 if format != "tar.gz" {
34 writeError(w, xrpcerr.NewXrpcError(
35 xrpcerr.WithTag("InvalidRequest"),
36 xrpcerr.WithMessage("only tar.gz format is supported"),
37 ), http.StatusBadRequest)
38 return
39 }
40
41 gr, err := git.Open(repoPath, ref)
42 if err != nil {
43 writeError(w, xrpcerr.NewXrpcError(
44 xrpcerr.WithTag("RefNotFound"),
45 xrpcerr.WithMessage("repository or ref not found"),
46 ), http.StatusNotFound)
47 return
48 }
49
50 repoParts := strings.Split(repo, "/")
51 repoName := repoParts[len(repoParts)-1]
52
53 safeRefFilename := strings.ReplaceAll(plumbing.ReferenceName(ref).Short(), "/", "-")
54
55 var archivePrefix string
56 if prefix != "" {
57 archivePrefix = prefix
58 } else {
59 archivePrefix = fmt.Sprintf("%s-%s", repoName, safeRefFilename)
60 }
61
62 filename := fmt.Sprintf("%s-%s.tar.gz", repoName, safeRefFilename)
63 w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
64 w.Header().Set("Content-Type", "application/gzip")
65
66 gw := gzip.NewWriter(w)
67 defer gw.Close()
68
69 err = gr.WriteTar(gw, archivePrefix)
70 if err != nil {
71 // once we start writing to the body we can't report error anymore
72 // so we are only left with logging the error
73 x.Logger.Error("writing tar file", "error", err.Error())
74 return
75 }
76
77 err = gw.Flush()
78 if err != nil {
79 // once we start writing to the body we can't report error anymore
80 // so we are only left with logging the error
81 x.Logger.Error("flushing", "error", err.Error())
82 return
83 }
84}