added git ssh support and ablity to download repo via zip, tar.gz, and bundle
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
gitdomain "github.com/forgeo/forgebucket/internal/domain/git"
|
||||
)
|
||||
|
||||
type ArchiveHandler struct {
|
||||
db *xorm.Engine
|
||||
}
|
||||
|
||||
func NewArchiveHandler(db *xorm.Engine) *ArchiveHandler {
|
||||
return &ArchiveHandler{db: db}
|
||||
}
|
||||
|
||||
var archiveFormats = map[string]struct {
|
||||
contentType string
|
||||
ext string
|
||||
}{
|
||||
"zip": {"application/zip", "zip"},
|
||||
"tar.gz": {"application/x-tar", "tar.gz"},
|
||||
"bundle": {"application/octet-stream", "bundle"},
|
||||
}
|
||||
|
||||
func (h *ArchiveHandler) Download(w http.ResponseWriter, r *http.Request) {
|
||||
repo, ok := resolveRepo(h.db, w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
format := r.URL.Query().Get("format")
|
||||
if format == "" {
|
||||
format = "zip"
|
||||
}
|
||||
meta, allowed := archiveFormats[format]
|
||||
if !allowed {
|
||||
jsonError(w, "format must be zip, tar.gz, or bundle", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ref := r.URL.Query().Get("ref")
|
||||
if ref == "" {
|
||||
ref = repo.DefaultBranch
|
||||
}
|
||||
if ref == "" {
|
||||
ref = "HEAD"
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("%s-%s.%s", repo.Name, ref, meta.ext)
|
||||
w.Header().Set("Content-Type", meta.contentType)
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
|
||||
|
||||
if err := gitdomain.ArchiveStream(repo.DiskPath, ref, format, w); err != nil {
|
||||
// Headers already written — can't change status code; just log and close.
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/forgeo/forgebucket/internal/config"
|
||||
)
|
||||
|
||||
type InstanceHandler struct {
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func NewInstanceHandler(cfg *config.Config) *InstanceHandler {
|
||||
return &InstanceHandler{cfg: cfg}
|
||||
}
|
||||
|
||||
// Get returns the public instance configuration needed by the frontend to
|
||||
// construct clone URLs (SSH host, SSH port, instance name).
|
||||
func (h *InstanceHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
sshHost := h.sshHost(r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]string{ //nolint:errcheck
|
||||
"sshHost": sshHost,
|
||||
"sshPort": h.cfg.SSHPort,
|
||||
"instanceName": h.cfg.InstanceName,
|
||||
})
|
||||
}
|
||||
|
||||
// sshHost extracts the hostname from InstanceURL. Falls back to the request
|
||||
// host when InstanceURL is unset (common in local development).
|
||||
func (h *InstanceHandler) sshHost(r *http.Request) string {
|
||||
if h.cfg.InstanceURL != "" {
|
||||
if u, err := url.Parse(h.cfg.InstanceURL); err == nil && u.Hostname() != "" {
|
||||
return u.Hostname()
|
||||
}
|
||||
}
|
||||
// Strip port from Host header if present.
|
||||
host := r.Host
|
||||
if u, err := url.Parse("http://" + host); err == nil {
|
||||
return u.Hostname()
|
||||
}
|
||||
return host
|
||||
}
|
||||
Reference in New Issue
Block a user