Skip to content

Commit

Permalink
Add support for expansion of direct children of query keys (#38)
Browse files Browse the repository at this point in the history
Thanks @C0urante !
  • Loading branch information
C0urante committed May 23, 2022
1 parent 7eeedaa commit b3896f0
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 32 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -150,6 +150,8 @@ g:
expand: issmirnov/dotfiles
s:
query: search?q=
ak:
expand: apache/kafka
z:
expand: issmirnov/zap
r:
Expand Down
8 changes: 8 additions & 0 deletions cmd/zap/config_test.go
Expand Up @@ -72,6 +72,14 @@ g:
expand: issmirnov/zap
s:
query: "search?q="
me:
expand: issmirnov
z:
expand: zap
ak:
query: apache/kafka
c:
query: +connect
z:
expand: zero.com
ssl_off: yes
Expand Down
45 changes: 30 additions & 15 deletions cmd/zap/text.go
Expand Up @@ -62,11 +62,17 @@ func getPrefix(c *gabs.Container) (string, int, error) {
return "", 0, fmt.Errorf("error in Config, no key matching 'expand', 'query', 'port' or 'schema' in %s", c.String())
}

// expandPath takes a Config, list of tokens (parsed from request) and the results buffer
// ExpandPath takes a Config, list of tokens (parsed from request) and the results buffer
// At each level of recursion, it matches the token to the action described in the Config, and writes it
// to the result buffer. There is special care needed to handle slashes correctly, which makes this function
// quite nontrivial. Tests are crucial to ensure correctness.
func expandPath(c *gabs.Container, token *list.Element, res *bytes.Buffer) {
func ExpandPath(c *gabs.Container, token *list.Element, res *bytes.Buffer) {
expandPath(c, token, res, true)
}

// Internal helper function that adds contextual information about whether a leading slash
// should be added to the beginning of the path
func expandPath(c *gabs.Container, token *list.Element, res *bytes.Buffer, prependSlash bool) {
if token == nil {
return
}
Expand All @@ -79,37 +85,46 @@ func expandPath(c *gabs.Container, token *list.Element, res *bytes.Buffer) {
return
}

prependChildSlash := true

switch action {
case expand: // Generic case, write slash followed by expanded token.
res.WriteString("/")
case expand: // Generic case: maybe write slash, then expanded token.
if prependSlash {
res.WriteString("/")
}
res.WriteString(p)

case query: // Write a slash + query string expansion, then perform token skipahead in order to have correct slashes.
res.WriteString("/")
res.WriteString(p)
if token.Next() != nil {
res.WriteString(token.Next().Value.(string))
token = token.Next()
case query: // Maybe write a slash, then expanded query, then recurse with no prepended slashes
if prependSlash {
res.WriteString("/")
}
res.WriteString(p)
prependChildSlash = false

case port: // A little bit of a special case - unlike "expand", we don't want a leading slash.
case port: // A little bit of a special case - unlike "expand" and "query", we never want a leading slash.
res.WriteString(p)

default:
panic("Programmer error, this should never happen.")
}
expandPath(child, token.Next(), res)
expandPath(child, token.Next(), res, prependChildSlash)
return
} else if child, ok := children[passKey]; ok {
res.WriteString("/")
if prependSlash {
res.WriteString("/")
}
res.WriteString(token.Value.(string))
expandPath(child, token.Next(), res)
expandPath(child, token.Next(), res, true)
return
}

// if tokens left over, append the rest
for e := token; e != nil; e = e.Next() {
res.WriteString("/")
if prependSlash {
res.WriteString("/")
} else {
prependSlash = true
}
res.WriteString(e.Value.(string))
}
}
Expand Down
78 changes: 63 additions & 15 deletions cmd/zap/text_test.go
Expand Up @@ -47,7 +47,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/issmirnov/zap'", func() {
So(res.String(), ShouldEqual, "https://github.com/issmirnov/zap")
Expand All @@ -59,7 +59,7 @@ func TestExpander(t *testing.T) {
// var res bytes.Buffer
// res.WriteString(httpsPrefix)
//
// expandPath(c, l.Front(), &res)
// ExpandPath(c, l.Front(), &res)
//
// Convey("result should equal 'https://example.com/999'", func() {
// So(res.String(), ShouldEqual, "https://example.com/999")
Expand All @@ -71,7 +71,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/issmirnov/zap/extratext'", func() {
So(res.String(), ShouldEqual, "https://github.com/issmirnov/zap/extratext")
Expand All @@ -83,7 +83,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/'", func() {
So(res.String(), ShouldEqual, "https://github.com/")
Expand All @@ -95,7 +95,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/issmirnov/zap/very/deep/path'", func() {
So(res.String(), ShouldEqual, "https://github.com/issmirnov/zap/very/deep/path")
Expand All @@ -107,7 +107,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=foobar'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=foobar")
Expand All @@ -119,7 +119,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=foo/bar/baz'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=foo/bar/baz")
Expand All @@ -131,7 +131,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=foo/bar/baz/'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=foo/bar/baz/")
Expand All @@ -143,7 +143,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/query/homebrew'", func() {
So(res.String(), ShouldEqual, "https://github.com/query/homebrew")
Expand All @@ -155,7 +155,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://wildcard.com/1/*/3/4'", func() {
So(res.String(), ShouldEqual, "https://wildcard.com/1/*/3/4")
Expand All @@ -167,7 +167,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://wildcard.com/1/2/3/4'", func() {
So(res.String(), ShouldEqual, "https://wildcard.com/1/2/3/4")
Expand All @@ -179,7 +179,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://kafka.apache.org/contact", func() {
So(res.String(), ShouldEqual, "https://kafka.apache.org/contact")
Expand All @@ -191,7 +191,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://kafka.apache.org/23", func() {
So(res.String(), ShouldEqual, "https://kafka.apache.org/23")
Expand All @@ -203,7 +203,7 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://kafka.apache.org/23/javadoc/index.html?overview-summary.html", func() {
So(res.String(), ShouldEqual, "https://kafka.apache.org/23/javadoc/index.html?overview-summary.html")
Expand All @@ -215,10 +215,58 @@ func TestExpander(t *testing.T) {
var res bytes.Buffer
res.WriteString(httpsPrefix)

expandPath(c, l.Front(), &res)
ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://kafka.apache.org/expand/javadoc/index.html?overview-summary.html", func() {
So(res.String(), ShouldEqual, "https://kafka.apache.org/expand/javadoc/index.html?overview-summary.html")
})
})
Convey("Given 'g/s/me'", t, func() {
c, _ := loadTestYaml()
l := tokenize("g/s/me")
var res bytes.Buffer
res.WriteString(httpsPrefix)

ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=issmirnov'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=issmirnov")
})
})
Convey("Given 'g/s/me/z'", t, func() {
c, _ := loadTestYaml()
l := tokenize("g/s/me/z")
var res bytes.Buffer
res.WriteString(httpsPrefix)

ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=issmirnov/zap'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=issmirnov/zap")
})
})
Convey("Given 'g/s/ak'", t, func() {
c, _ := loadTestYaml()
l := tokenize("g/s/ak")
var res bytes.Buffer
res.WriteString(httpsPrefix)

ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=apache/kafka'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=apache/kafka")
})
})
Convey("Given 'g/s/ak/c'", t, func() {
c, _ := loadTestYaml()
l := tokenize("g/s/ak/c")
var res bytes.Buffer
res.WriteString(httpsPrefix)

ExpandPath(c, l.Front(), &res)

Convey("result should equal 'https://github.com/search?q=apache/kafka+connect'", func() {
So(res.String(), ShouldEqual, "https://github.com/search?q=apache/kafka+connect")
})
})
}
2 changes: 1 addition & 1 deletion cmd/zap/web.go
Expand Up @@ -48,7 +48,7 @@ func IndexHandler(ctx *Context, w http.ResponseWriter, r *http.Request) (int, er
path.WriteString(httpsPrefix)
}

expandPath(conf, tokensStart, &path)
ExpandPath(conf, tokensStart, &path)

// send result
http.Redirect(w, r, path.String(), http.StatusFound)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -14,7 +14,7 @@ require (
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945
github.com/spf13/afero v1.2.2
golang.org/x/exp/errors v0.0.0-20200901203048-c4f52b2c50aa
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -37,6 +37,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY=
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
Expand Down

0 comments on commit b3896f0

Please sign in to comment.