chore: mercury changes
This commit is contained in:
@@ -62,10 +62,16 @@ func (lis Config) ToSpaceMap() SpaceMap {
|
||||
|
||||
// String format config as string
|
||||
func (lis Config) String() string {
|
||||
attLen := 0
|
||||
tagLen := 0
|
||||
|
||||
for _, o := range lis {
|
||||
var buf strings.Builder
|
||||
for i, o := range lis {
|
||||
attLen := 0
|
||||
tagLen := 0
|
||||
|
||||
if i > 0 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
for _, v := range o.List {
|
||||
l := len(v.Name)
|
||||
if attLen <= l {
|
||||
@@ -77,10 +83,7 @@ func (lis Config) String() string {
|
||||
tagLen = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
for _, o := range lis {
|
||||
if len(o.Notes) > 0 {
|
||||
buf.WriteString("# ")
|
||||
buf.WriteString(strings.Join(o.Notes, "\n# "))
|
||||
@@ -133,7 +136,10 @@ func (lis Config) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteRune('\n')
|
||||
for _, line := range o.Trailer {
|
||||
buf.WriteString(line)
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
@@ -188,11 +194,21 @@ func (lis Config) EnvString() string {
|
||||
func (lis Config) INIString() string {
|
||||
var buf strings.Builder
|
||||
for _, o := range lis {
|
||||
for _, note := range o.Notes {
|
||||
buf.WriteString("; ")
|
||||
buf.WriteString(note)
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
buf.WriteRune('[')
|
||||
buf.WriteString(o.Space)
|
||||
buf.WriteRune(']')
|
||||
buf.WriteRune('\n')
|
||||
for _, v := range o.List {
|
||||
for _, note := range v.Notes {
|
||||
buf.WriteString("; ")
|
||||
buf.WriteString(note)
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
buf.WriteString(v.Name)
|
||||
switch len(v.Values) {
|
||||
case 0:
|
||||
@@ -221,6 +237,13 @@ func (lis Config) INIString() string {
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, line := range o.Trailer {
|
||||
buf.WriteString("; ")
|
||||
buf.WriteString(line)
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
@@ -228,10 +251,16 @@ func (lis Config) INIString() string {
|
||||
|
||||
// String format config as string
|
||||
func (lis Config) HTMLString() string {
|
||||
attLen := 0
|
||||
tagLen := 0
|
||||
|
||||
for _, o := range lis {
|
||||
var buf strings.Builder
|
||||
for i, o := range lis {
|
||||
attLen := 0
|
||||
tagLen := 0
|
||||
|
||||
if i > 0 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
for _, v := range o.List {
|
||||
l := len(v.Name)
|
||||
if attLen <= l {
|
||||
@@ -243,10 +272,7 @@ func (lis Config) HTMLString() string {
|
||||
tagLen = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
for _, o := range lis {
|
||||
if len(o.Notes) > 0 {
|
||||
buf.WriteString("<i>")
|
||||
buf.WriteString("# ")
|
||||
@@ -311,7 +337,12 @@ func (lis Config) HTMLString() string {
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteRune('\n')
|
||||
for _, line := range o.Trailer {
|
||||
buf.WriteString("<small>")
|
||||
buf.WriteString(line)
|
||||
buf.WriteString("</small>")
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
@@ -319,10 +350,11 @@ func (lis Config) HTMLString() string {
|
||||
|
||||
// Space stores a registry of spaces
|
||||
type Space struct {
|
||||
Space string `json:"space"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Notes []string `json:"notes,omitempty"`
|
||||
List []Value `json:"list,omitempty"`
|
||||
Space string `json:"space"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Notes []string `json:"notes,omitempty"`
|
||||
List []Value `json:"list,omitempty"`
|
||||
Trailer []string `json:"trailer,omitempty"`
|
||||
}
|
||||
|
||||
func NewSpace(space string) *Space {
|
||||
@@ -437,7 +469,7 @@ type SpaceMap map[string]*Space
|
||||
func (m SpaceMap) Space(name string) (*Space, bool) {
|
||||
s, ok := m[name]
|
||||
return s, ok
|
||||
}
|
||||
}
|
||||
|
||||
// Rule is a type of rule
|
||||
type Rule struct {
|
||||
|
||||
@@ -20,17 +20,11 @@ type NamespaceSearch []NamespaceSpec
|
||||
func ParseNamespace(ns string) (lis NamespaceSearch) {
|
||||
for _, part := range strings.Split(ns, ";") {
|
||||
if strings.HasPrefix(part, "trace:") {
|
||||
for _, s := range strings.Split(part[6:], ",") {
|
||||
lis = append(lis, NamespaceTrace(s))
|
||||
}
|
||||
lis = append(lis, NamespaceTrace(part[6:]))
|
||||
} else if strings.Contains(part, "*") {
|
||||
lis = append(lis, NamespaceStar(part))
|
||||
} else {
|
||||
for _, s := range strings.Split(part, ",") {
|
||||
if strings.Contains(s, "*") {
|
||||
lis = append(lis, NamespaceStar(s))
|
||||
} else {
|
||||
lis = append(lis, NamespaceNode(s))
|
||||
}
|
||||
}
|
||||
lis = append(lis, NamespaceNode(part))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +38,7 @@ func (n NamespaceSearch) String() string {
|
||||
for _, v := range n {
|
||||
lis = append(lis, v.String())
|
||||
}
|
||||
return strings.Join(lis, ",")
|
||||
return strings.Join(lis, ";")
|
||||
}
|
||||
|
||||
// Match returns true if any match.
|
||||
|
||||
59
mercury/namespace_test.go
Normal file
59
mercury/namespace_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package mercury_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
"go.sour.is/pkg/mercury"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
||||
func TestNamespaceParse(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in string
|
||||
out string
|
||||
args []any
|
||||
}{
|
||||
{
|
||||
in: "d42.bgp.kapha.*;trace:d42.bgp.kapha",
|
||||
out: "(column LIKE ? OR ? LIKE column || '%')",
|
||||
args: []any{"d42.bgp.kapha.%", "d42.bgp.kapha"},
|
||||
},
|
||||
|
||||
{
|
||||
in: "d42.bgp.kapha.*,d42.bgp.kapha",
|
||||
out: "(column LIKE ? OR column = ?)",
|
||||
args: []any{"d42.bgp.kapha.%", "d42.bgp.kapha"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) {
|
||||
is := is.New(t)
|
||||
out := mercury.ParseNamespace(tt.in)
|
||||
sql, args, err := getWhere(out).ToSql()
|
||||
is.NoErr(err)
|
||||
is.Equal(sql, tt.out)
|
||||
is.Equal(args, tt.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getWhere(search mercury.NamespaceSearch) sq.Sqlizer {
|
||||
var where sq.Or
|
||||
space := "column"
|
||||
for _, m := range search {
|
||||
switch m.(type) {
|
||||
case mercury.NamespaceNode:
|
||||
where = append(where, sq.Eq{space: m.Value()})
|
||||
case mercury.NamespaceStar:
|
||||
where = append(where, sq.Like{space: m.Value()})
|
||||
case mercury.NamespaceTrace:
|
||||
e := sq.Expr(`? LIKE `+space+` || '%'`, m.Value())
|
||||
where = append(where, e)
|
||||
}
|
||||
}
|
||||
return where
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package mercury
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -49,6 +50,26 @@ func ParseText(body io.Reader) (config SpaceMap, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "----") && strings.HasSuffix(line, "----") {
|
||||
var trailer []string
|
||||
|
||||
trailer = append(trailer, line)
|
||||
for scanner.Scan() {
|
||||
line = scanner.Text()
|
||||
trailer = append(trailer, line)
|
||||
if strings.HasPrefix(line, "----") && strings.HasSuffix(line, "----") {
|
||||
break
|
||||
}
|
||||
}
|
||||
c, ok := config[space]
|
||||
if !ok {
|
||||
c = &Space{Space: space}
|
||||
}
|
||||
log.Println(trailer)
|
||||
c.Trailer = append(c.Trailer, trailer...)
|
||||
config[space] = c
|
||||
continue
|
||||
}
|
||||
if space == "" {
|
||||
continue
|
||||
}
|
||||
@@ -59,10 +80,8 @@ func ParseText(body io.Reader) (config SpaceMap, err error) {
|
||||
}
|
||||
|
||||
if strings.TrimSpace(sp[0]) == "" {
|
||||
var c *Space
|
||||
var ok bool
|
||||
|
||||
if c, ok = config[space]; !ok {
|
||||
c, ok := config[space]
|
||||
if !ok {
|
||||
c = &Space{Space: space}
|
||||
}
|
||||
|
||||
@@ -78,10 +97,8 @@ func ParseText(body io.Reader) (config SpaceMap, err error) {
|
||||
tags = fields[1:]
|
||||
}
|
||||
|
||||
var c *Space
|
||||
var ok bool
|
||||
|
||||
if c, ok = config[space]; !ok {
|
||||
c, ok := config[space]
|
||||
if !ok {
|
||||
c = &Space{Space: space}
|
||||
}
|
||||
|
||||
|
||||
28
mercury/parse_test.go
Normal file
28
mercury/parse_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package mercury_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
"go.sour.is/pkg/mercury"
|
||||
)
|
||||
|
||||
func TestParseText(t *testing.T) {
|
||||
is := is.New(t)
|
||||
sm, err := mercury.ParseText(strings.NewReader(`
|
||||
@test.sign
|
||||
key :value1
|
||||
-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
|
||||
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
|
||||
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
|
||||
acrdDxmq2S+oysQbK+pMUE
|
||||
-----END SSH SIGNATURE-----
|
||||
`))
|
||||
is.NoErr(err)
|
||||
for _, c := range sm {
|
||||
is.Equal(len(c.Trailer), 6)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
<br />
|
||||
<textarea name="content" rows="45" wrap="off"
|
||||
onkeyup="if (this.scrollHeight > this.clientHeight) this.style.height = this.scrollHeight + ' px';"
|
||||
style="overflow:auto; overflow-y:hidden; transition: height 0.2s ease-out;"></textarea>
|
||||
style="overflow:auto; transition: height 0.2s ease-out;"></textarea>
|
||||
</form>
|
||||
<pre id="space-saved"></pre>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background: rgb(210, 221, 240);
|
||||
}
|
||||
|
||||
header {
|
||||
@@ -57,6 +58,11 @@ code i {
|
||||
}
|
||||
|
||||
code em {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
code small {
|
||||
font-size-adjust: 50%;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
@@ -94,7 +100,7 @@ footer>span {
|
||||
.container>div {
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
background: rgb(238, 174, 202);
|
||||
background-color: white;
|
||||
border: 0px ;
|
||||
}
|
||||
|
||||
@@ -158,7 +164,7 @@ footer>span {
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
html, body {
|
||||
color: white;
|
||||
background: #111
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.sour.is/pkg/lg"
|
||||
"go.sour.is/pkg/ident"
|
||||
"go.sour.is/pkg/lg"
|
||||
"go.sour.is/pkg/rsql"
|
||||
"go.sour.is/pkg/set"
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -122,16 +122,32 @@ func (r *registry) Register(name string, h func(*Space) any) {
|
||||
func (r *registry) Configure(m SpaceMap) error {
|
||||
r.resetMatchers()
|
||||
for space, c := range m {
|
||||
space = strings.TrimPrefix(space, "mercury.source.")
|
||||
handler, name, _ := strings.Cut(space, ".")
|
||||
matches := c.FirstValue("match")
|
||||
for _, match := range matches.Values {
|
||||
ps := strings.Fields(match)
|
||||
priority, err := strconv.Atoi(ps[0])
|
||||
if err != nil {
|
||||
return err
|
||||
if strings.HasPrefix(space, "mercury.source.") {
|
||||
space = strings.TrimPrefix(space, "mercury.source.")
|
||||
handler, name, _ := strings.Cut(space, ".")
|
||||
matches := c.FirstValue("match")
|
||||
for _, match := range matches.Values {
|
||||
ps := strings.Fields(match)
|
||||
priority, err := strconv.Atoi(ps[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.add(name, handler, ps[1], priority, c)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(space, "mercury.output.") {
|
||||
space = strings.TrimPrefix(space, "mercury.output.")
|
||||
handler, name, _ := strings.Cut(space, ".")
|
||||
matches := c.FirstValue("match")
|
||||
for _, match := range matches.Values {
|
||||
ps := strings.Fields(match)
|
||||
priority, err := strconv.Atoi(ps[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.add(name, handler, ps[1], priority, c)
|
||||
}
|
||||
r.add(name, handler, ps[1], priority, c)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package mercury
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"sort"
|
||||
@@ -11,8 +13,8 @@ import (
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/golang/gddo/httputil"
|
||||
"go.sour.is/pkg/lg"
|
||||
"go.sour.is/pkg/ident"
|
||||
"go.sour.is/pkg/lg"
|
||||
)
|
||||
|
||||
type root struct{}
|
||||
@@ -21,8 +23,13 @@ func NewHTTP() *root {
|
||||
return &root{}
|
||||
}
|
||||
|
||||
//go:embed public
|
||||
var public embed.FS
|
||||
|
||||
func (s *root) RegisterHTTP(mux *http.ServeMux) {
|
||||
mux.Handle("/", http.FileServer(http.Dir("./mercury/public")))
|
||||
// mux.Handle("/", http.FileServer(http.Dir("./mercury/public")))
|
||||
public, _ := fs.Sub(public, "public")
|
||||
mux.Handle("/", http.FileServerFS(public))
|
||||
}
|
||||
func (s *root) RegisterAPIv1(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /mercury", s.indexV1)
|
||||
@@ -30,6 +37,9 @@ func (s *root) RegisterAPIv1(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /mercury/config", s.configV1)
|
||||
mux.HandleFunc("POST /mercury/config", s.storeV1)
|
||||
}
|
||||
func (s *root) RegisterWellKnown(mux *http.ServeMux) {
|
||||
s.RegisterAPIv1(mux)
|
||||
}
|
||||
|
||||
func (s *root) configV1(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodPost {
|
||||
@@ -62,7 +72,7 @@ func (s *root) configV1(w http.ResponseWriter, r *http.Request) {
|
||||
log.Print("SPC: ", space)
|
||||
ns := ParseNamespace(space)
|
||||
log.Print("PRE: ", ns)
|
||||
ns = rules.ReduceSearch(ns)
|
||||
//ns = rules.ReduceSearch(ns)
|
||||
log.Print("POST: ", ns)
|
||||
|
||||
lis, err := Registry.GetConfig(ctx, ns.String(), "", "")
|
||||
|
||||
@@ -6,6 +6,7 @@ CREATE TABLE IF NOT EXISTS mercury_spaces
|
||||
id integer NOT NULL DEFAULT nextval('mercury_spaces_id_seq'::regclass),
|
||||
notes character varying[] NOT NULL DEFAULT '{}'::character varying[],
|
||||
tags character varying[] NOT NULL DEFAULT '{}'::character varying[],
|
||||
trailer character varying[] NOT NULL DEFAULT '{}'::character varying[],
|
||||
CONSTRAINT mercury_namespace_pk PRIMARY KEY (id)
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS mercury_namespace_space_uindex
|
||||
@@ -35,7 +36,8 @@ CREATE OR REPLACE VIEW mercury_registry_vw
|
||||
v.name,
|
||||
v."values",
|
||||
v.notes,
|
||||
v.tags
|
||||
v.tags,
|
||||
s.trailer
|
||||
FROM mercury_spaces s
|
||||
JOIN mercury_values v ON s.id = v.id;
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ CREATE TABLE IF NOT EXISTS mercury_spaces
|
||||
space character varying NOT NULL unique,
|
||||
id integer NOT NULL CONSTRAINT mercury_namespace_pk PRIMARY KEY autoincrement,
|
||||
notes json NOT NULL DEFAULT '[]',
|
||||
tags json NOT NULL DEFAULT '[]'
|
||||
tags json NOT NULL DEFAULT '[]',
|
||||
trailer json NOT NULL DEFAULT '[]'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS mercury_values
|
||||
@@ -27,7 +28,8 @@ CREATE VIEW if not exists mercury_registry_vw
|
||||
v.name,
|
||||
v."values",
|
||||
v.notes,
|
||||
v.tags
|
||||
v.tags,
|
||||
s.trailer
|
||||
FROM mercury_spaces s
|
||||
JOIN mercury_values v ON s.id = v.id;
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ func (p *sqlHandler) listSpace(ctx context.Context, tx sq.BaseRunner, where sq.S
|
||||
tx = p.db
|
||||
}
|
||||
|
||||
query := sq.Select(`"id"`, `"space"`, `"tags"`, `"notes"`).
|
||||
query := sq.Select(`"id"`, `"space"`, `"notes"`, `"tags"`, `"trailer"`).
|
||||
From("mercury_spaces").
|
||||
Where(where).
|
||||
OrderBy("space asc").
|
||||
@@ -189,6 +189,7 @@ func (p *sqlHandler) listSpace(ctx context.Context, tx sq.BaseRunner, where sq.S
|
||||
&s.Space.Space,
|
||||
listScan(&s.Space.Notes, p.listFormat),
|
||||
listScan(&s.Space.Tags, p.listFormat),
|
||||
listScan(&s.Trailer, p.listFormat),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -287,6 +288,7 @@ func (p *sqlHandler) WriteConfig(ctx context.Context, config mercury.Config) (er
|
||||
Where(sq.Eq{"id": updateIDs[i]}).
|
||||
Set("tags", listValue(u.Tags, p.listFormat)).
|
||||
Set("notes", listValue(u.Notes, p.listFormat)).
|
||||
Set("trailer", listValue(u.Trailer, p.listFormat)).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
span.AddEvent(lg.LogQuery(query.ToSql()))
|
||||
_, err := query.RunWith(tx).ExecContext(ctx)
|
||||
@@ -305,8 +307,13 @@ func (p *sqlHandler) WriteConfig(ctx context.Context, config mercury.Config) (er
|
||||
var id uint64
|
||||
query := sq.Insert("mercury_spaces").
|
||||
PlaceholderFormat(sq.Dollar).
|
||||
Columns("space", "tags", "notes").
|
||||
Values(s.Space, listValue(s.Tags, p.listFormat), listValue(s.Notes, p.listFormat)).
|
||||
Columns("space", "tags", "notes", "trailer").
|
||||
Values(
|
||||
s.Space,
|
||||
listValue(s.Tags, p.listFormat),
|
||||
listValue(s.Notes, p.listFormat),
|
||||
listValue(s.Trailer, p.listFormat),
|
||||
).
|
||||
Suffix("RETURNING \"id\"")
|
||||
span.AddEvent(lg.LogQuery(query.ToSql()))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user