dlset: allow globs in name, short kind
This commit is contained in:
		@ -6,6 +6,7 @@ import (
 | 
				
			|||||||
	"encoding/base32"
 | 
						"encoding/base32"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"slices"
 | 
						"slices"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@ -16,6 +17,11 @@ import (
 | 
				
			|||||||
	"m.cluseau.fr/go/httperr"
 | 
						"m.cluseau.fr/go/httperr"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func globMatch(pattern, value string) bool {
 | 
				
			||||||
 | 
						ok, _ := filepath.Match(pattern, value)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DownloadSet struct {
 | 
					type DownloadSet struct {
 | 
				
			||||||
	Expiry time.Time
 | 
						Expiry time.Time
 | 
				
			||||||
	Items  []DownloadSetItem
 | 
						Items  []DownloadSetItem
 | 
				
			||||||
@ -23,7 +29,7 @@ type DownloadSet struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (s DownloadSet) Contains(kind, name, asset string) bool {
 | 
					func (s DownloadSet) Contains(kind, name, asset string) bool {
 | 
				
			||||||
	for _, item := range s.Items {
 | 
						for _, item := range s.Items {
 | 
				
			||||||
		if item.Kind == kind && item.Name == name &&
 | 
							if item.Kind == kind && globMatch(item.Name, name) &&
 | 
				
			||||||
			slices.Contains(item.Assets, asset) {
 | 
								slices.Contains(item.Assets, asset) {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -76,7 +82,15 @@ type DownloadSetItem struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i DownloadSetItem) EncodeTo(buf *strings.Builder) {
 | 
					func (i DownloadSetItem) EncodeTo(buf *strings.Builder) {
 | 
				
			||||||
	buf.WriteString(i.Kind)
 | 
						kind := i.Kind
 | 
				
			||||||
 | 
						switch kind {
 | 
				
			||||||
 | 
						case "host":
 | 
				
			||||||
 | 
							kind = "h"
 | 
				
			||||||
 | 
						case "cluster":
 | 
				
			||||||
 | 
							kind = "c"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf.WriteString(kind)
 | 
				
			||||||
	buf.WriteByte(':')
 | 
						buf.WriteByte(':')
 | 
				
			||||||
	buf.WriteString(i.Name)
 | 
						buf.WriteString(i.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,6 +103,14 @@ func (i DownloadSetItem) EncodeTo(buf *strings.Builder) {
 | 
				
			|||||||
func (i *DownloadSetItem) Decode(encoded string) {
 | 
					func (i *DownloadSetItem) Decode(encoded string) {
 | 
				
			||||||
	rem := encoded
 | 
						rem := encoded
 | 
				
			||||||
	i.Kind, rem, _ = strings.Cut(rem, ":")
 | 
						i.Kind, rem, _ = strings.Cut(rem, ":")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch i.Kind {
 | 
				
			||||||
 | 
						case "h":
 | 
				
			||||||
 | 
							i.Kind = "host"
 | 
				
			||||||
 | 
						case "c":
 | 
				
			||||||
 | 
							i.Kind = "cluster"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i.Name, rem, _ = strings.Cut(rem, ":")
 | 
						i.Name, rem, _ = strings.Cut(rem, ":")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if rem == "" {
 | 
						if rem == "" {
 | 
				
			||||||
@ -230,10 +252,8 @@ func wsDownloadSet(req *restful.Request, resp *restful.Response) {
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
  <title>` + err.Error() + `</title>
 | 
					  <title>` + err.Error() + `</title>
 | 
				
			||||||
  <style>
 | 
					  <style src="/ui/style.css"/>
 | 
				
			||||||
    @import url('/ui/style.css');
 | 
					  <style src="/ui/app.css"/>
 | 
				
			||||||
    @import url('/ui/app.css');
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body><h1>` + err.Error() + `</h1></body>
 | 
					<body><h1>` + err.Error() + `</h1></body>
 | 
				
			||||||
</html>`))
 | 
					</html>`))
 | 
				
			||||||
@ -245,22 +265,44 @@ func wsDownloadSet(req *restful.Request, resp *restful.Response) {
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
  <title>Download set</title>
 | 
					  <title>Download set</title>
 | 
				
			||||||
  <style>
 | 
					  <style src="/ui/style.css"/>
 | 
				
			||||||
    @import url('/ui/style.css');
 | 
					  <style src="/ui/app.css"/>
 | 
				
			||||||
    @import url('/ui/app.css');
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body><h1>Download set</h1>
 | 
					<body><h1>Download set</h1>
 | 
				
			||||||
`)
 | 
					`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cfg, err2 := readConfig()
 | 
				
			||||||
 | 
						if err2 != nil {
 | 
				
			||||||
 | 
							wsError(resp, err2)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, item := range set.Items {
 | 
						for _, item := range set.Items {
 | 
				
			||||||
		fmt.Fprintf(buf, "<h2>%s %s</h2>", strings.Title(item.Kind), item.Name)
 | 
							names := make([]string, 0)
 | 
				
			||||||
 | 
							switch item.Kind {
 | 
				
			||||||
 | 
							case "cluster":
 | 
				
			||||||
 | 
								for _, c := range cfg.Clusters {
 | 
				
			||||||
 | 
									if globMatch(item.Name, c.Name) {
 | 
				
			||||||
 | 
										names = append(names, c.Name)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case "host":
 | 
				
			||||||
 | 
								for _, h := range cfg.Hosts {
 | 
				
			||||||
 | 
									if globMatch(item.Name, h.Name) {
 | 
				
			||||||
 | 
										names = append(names, h.Name)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, name := range names {
 | 
				
			||||||
 | 
								fmt.Fprintf(buf, "<h2>%s %s</h2>", strings.Title(item.Kind), name)
 | 
				
			||||||
			fmt.Fprintf(buf, "<p class=\"download-links\">\n")
 | 
								fmt.Fprintf(buf, "<p class=\"download-links\">\n")
 | 
				
			||||||
			for _, asset := range item.Assets {
 | 
								for _, asset := range item.Assets {
 | 
				
			||||||
			fmt.Fprintf(buf, "  <a href=\"/public/download-set/%s/%s/%s?set=%s\" download>%s</a>\n", item.Kind, item.Name, asset, setStr, asset)
 | 
									fmt.Fprintf(buf, "  <a href=\"/public/download-set/%s/%s/%s?set=%s\" download>%s</a>\n", item.Kind, name, asset, setStr, asset)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			fmt.Fprintf(buf, `</p>`)
 | 
								fmt.Fprintf(buf, `</p>`)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf.WriteString("</body></html>")
 | 
						buf.WriteString("</body></html>")
 | 
				
			||||||
	buf.WriteTo(resp)
 | 
						buf.WriteTo(resp)
 | 
				
			||||||
 | 
				
			|||||||
@ -184,10 +184,8 @@ func wsDownloadPage(req *restful.Request, resp *restful.Response) {
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
  <title>Token not found</title>
 | 
					  <title>Token not found</title>
 | 
				
			||||||
  <style>
 | 
					  <style src="/ui/style.css"/>
 | 
				
			||||||
    @import url('/ui/style.css');
 | 
					  <style src="/ui/app.css"/>
 | 
				
			||||||
    @import url('/ui/app.css');
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body><h1>Token not found</h1></body>
 | 
					<body><h1>Token not found</h1></body>
 | 
				
			||||||
</html>`))
 | 
					</html>`))
 | 
				
			||||||
@ -199,10 +197,8 @@ func wsDownloadPage(req *restful.Request, resp *restful.Response) {
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
  <title>Token assets: %s %s</title>
 | 
					  <title>Token assets: %s %s</title>
 | 
				
			||||||
  <style>
 | 
					  <style src="/ui/style.css"/>
 | 
				
			||||||
    @import url('/ui/style.css');
 | 
					  <style src="/ui/app.css"/>
 | 
				
			||||||
    @import url('/ui/app.css');
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body><h1>Token assets: %s %s</h1>
 | 
					<body><h1>Token assets: %s %s</h1>
 | 
				
			||||||
<ul>
 | 
					<ul>
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user