Skip to content

Commit

Permalink
new features and new fixes
Browse files Browse the repository at this point in the history
* add select to disambiguate assets, use select=substr to filter matched assets
* add move=1 as a ! (bang) alternative, sometimes the ! breaks some HTTP routers
* add type=json to output result as json
* match 686 to 32-bit
* show resolved release rather than "latest"
  • Loading branch information
jpillora committed Aug 5, 2024
1 parent 827ef6e commit daba077
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 26 deletions.
32 changes: 23 additions & 9 deletions handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ var (
)

type Query struct {
User, Program, AsProgram, Release string
MoveToPath, Search, Insecure bool
SudoMove bool // deprecated: not used, now automatically detected
User, Program, Release string
AsProgram, Select string
MoveToPath, Search, Insecure bool
SudoMove bool // deprecated: not used, now automatically detected
}

type Result struct {
Query
Timestamp time.Time
Assets Assets
M1Asset bool
ResolvedResolve string
Timestamp time.Time
Assets Assets
M1Asset bool
}

func (q Query) cacheKey() string {
Expand Down Expand Up @@ -90,6 +92,10 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, cleaned, http.StatusInternalServerError)
}
switch qtype {
case "json":
w.Header().Set("Content-Type", "application/json")
ext = "json"
script = ""
case "script":
w.Header().Set("Content-Type", "text/x-shellscript")
ext = "sh"
Expand All @@ -112,6 +118,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Release: "",
Insecure: r.URL.Query().Get("insecure") == "1",
AsProgram: r.URL.Query().Get("as"),
Select: r.URL.Query().Get("select"),
}
// set query from route
path := strings.TrimPrefix(r.URL.Path, "/")
Expand All @@ -120,6 +127,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
q.MoveToPath = true
path = strings.TrimRight(path, "!")
}
if r.URL.Query().Get("move") == "1" {
q.MoveToPath = true // also allow move=1 if bang in urls cause issues
}
var rest string
q.User, rest = splitHalf(path, "/")
q.Program, q.Release = splitHalf(rest, "@")
Expand Down Expand Up @@ -160,6 +170,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
showError(err.Error(), http.StatusBadGateway)
return
}
// no render script? just output as json
if script == "" {
b, _ := json.MarshalIndent(result, "", " ")
w.Write(b)
return
}
// load template
t, err := template.New("installer").Parse(script)
if err != nil {
Expand All @@ -172,7 +188,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
showError("Template error: "+err.Error(), http.StatusInternalServerError)
return
}
log.Printf("serving script %s/%s@%s (%s)", q.User, q.Program, q.Release, ext)
log.Printf("serving script %s/%s@%s (%s)", result.User, result.Program, result.Release, ext)
// ready
w.Write(buff.Bytes())
}
Expand Down Expand Up @@ -228,10 +244,8 @@ func (h *Handler) get(url string, v interface{}) error {
b, _ := io.ReadAll(resp.Body)
return errors.New(http.StatusText(resp.StatusCode) + " " + string(b))
}

if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
return fmt.Errorf("download failed: %s: %s", url, err)
}

return nil
}
45 changes: 32 additions & 13 deletions handler/handler_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"log"
"net/http"
"sort"
"strings"
"time"
)
Expand Down Expand Up @@ -55,10 +56,11 @@ func (h *Handler) execute(q Query) (Result, error) {
q.Release = release
}
result := Result{
Timestamp: ts,
Query: q,
Assets: assets,
M1Asset: assets.HasM1(),
Timestamp: ts,
Query: q,
ResolvedResolve: release,
Assets: assets,
M1Asset: assets.HasM1(),
}
//success store results
h.cacheMut.Lock()
Expand Down Expand Up @@ -110,8 +112,7 @@ func (h *Handler) getAssetsNoCache(q Query) (string, Assets, error) {
if l := len(sumIndex); l > 0 {
log.Printf("fetched %d asset shasums", l)
}
assets := Assets{}
index := map[string]bool{}
index := map[string]Asset{}
for _, ga := range ghas {
url := ga.BrowserDownloadURL
//only binary containers are supported
Expand Down Expand Up @@ -142,7 +143,11 @@ func (h *Handler) getAssetsNoCache(q Query) (string, Assets, error) {
log.Printf("fetched asset has unknown os: %s", ga.Name)
continue
}
log.Printf("fetched asset: %s", ga.Name)
// user selecting a particular asset?
if q.Select != "" && !strings.Contains(ga.Name, q.Select) {
log.Printf("select excludes asset: %s", ga.Name)
continue
}
asset := Asset{
OS: os,
Arch: arch,
Expand All @@ -152,16 +157,30 @@ func (h *Handler) getAssetsNoCache(q Query) (string, Assets, error) {
SHA256: sumIndex[ga.Name],
}
//there can only be 1 file for each OS/Arch
if index[asset.Key()] {
continue
key := asset.Key()
other, exists := index[key]
if exists {
gnu := func(s string) bool { return strings.Contains(s, "gnu") }
musl := func(s string) bool { return strings.Contains(s, "musl") }
g2m := gnu(other.Name) && !musl(other.Name) && !gnu(asset.Name) && musl(asset.Name)
// prefer musl over glib for portability, override with select=gnu
if !g2m {
continue
}
}
index[asset.Key()] = true
//include!
assets = append(assets, asset)
index[key] = asset
}
if len(assets) == 0 {
if len(index) == 0 {
return release, nil, errors.New("no downloads found for this release")
}
assets := Assets{}
for _, a := range index {
log.Printf("including asset: %s (%s)", a.Name, a.Key())
assets = append(assets, a)
}
sort.Slice(assets, func(i, j int) bool {
return assets[i].Key() < assets[j].Key()
})
return release, assets, nil
}

Expand Down
4 changes: 2 additions & 2 deletions handler/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

var (
archRe = regexp.MustCompile(`(arm64|arm|386|amd64|x86_64|aarch64|32|64)`)
archRe = regexp.MustCompile(`(arm64|arm|386|686|amd64|x86_64|aarch64|32|64)`)
fileExtRe = regexp.MustCompile(`(\.tar)?(\.[a-z][a-z0-9]+)$`)
posixOSRe = regexp.MustCompile(`(darwin|linux|(net|free|open)bsd|mac|osx|windows|win)`)
checksumRe = regexp.MustCompile(`(checksums|sha256sums)`)
Expand All @@ -30,7 +30,7 @@ func getArch(s string) string {
//arch modifications
if a == "64" || a == "x86_64" || a == "" {
a = "amd64" //default
} else if a == "32" {
} else if a == "32" || a == "686" {
a = "386"
} else if a == "aarch64" {
a = "arm64"
Expand Down
2 changes: 1 addition & 1 deletion scripts/install.sh.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function install {
PROG="{{ .Program }}"
ASPROG="{{ .AsProgram }}"
MOVE="{{ .MoveToPath }}"
RELEASE="{{ .Release }}"
RELEASE="{{ .Release }}" # {{ .ResolvedResolve }}
INSECURE="{{ .Insecure }}"
OUT_DIR="{{ if .MoveToPath }}/usr/local/bin{{ else }}$(pwd){{ end }}"
GH="https://github.com"
Expand Down
3 changes: 2 additions & 1 deletion scripts/install.txt.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ repository: https://github.com/{{ .User }}/{{ .Program }}
user: {{ .User }}
program: {{ .Program }}{{if .AsProgram }}
as: {{ .AsProgram }}{{end}}
release: {{ .Release }}
release: {{ .ResolvedResolve }}
move-into-path: {{ .MoveToPath }}
sudo-move: {{ .SudoMove }}
used-search: {{ .Search }}
asset-select: {{ .Select }}

release assets:
{{ range .Assets }} {{ .Key }}
Expand Down

0 comments on commit daba077

Please sign in to comment.