Skip to content

Commit aca4002

Browse files
authored
caddyfile: Pass blocks to import for snippets (#6130)
* a * a * a * a * a * a
1 parent 8e0d3e1 commit aca4002

File tree

5 files changed

+337
-2
lines changed

5 files changed

+337
-2
lines changed

caddyconfig/caddyfile/parse.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,45 @@ func (p *parser) doImport(nesting int) error {
364364
// set up a replacer for non-variadic args replacement
365365
repl := makeArgsReplacer(args)
366366

367+
// grab all the tokens (if it exists) from within a block that follows the import
368+
var blockTokens []Token
369+
for currentNesting := p.Nesting(); p.NextBlock(currentNesting); {
370+
blockTokens = append(blockTokens, p.Token())
371+
}
372+
// initialize with size 1
373+
blockMapping := make(map[string][]Token, 1)
374+
if len(blockTokens) > 0 {
375+
// use such tokens to create a new dispenser, and then use it to parse each block
376+
bd := NewDispenser(blockTokens)
377+
for bd.Next() {
378+
// see if we can grab a key
379+
var currentMappingKey string
380+
if bd.Val() == "{" {
381+
return p.Err("anonymous blocks are not supported")
382+
}
383+
currentMappingKey = bd.Val()
384+
currentMappingTokens := []Token{}
385+
// read all args until end of line / {
386+
if bd.NextArg() {
387+
currentMappingTokens = append(currentMappingTokens, bd.Token())
388+
for bd.NextArg() {
389+
currentMappingTokens = append(currentMappingTokens, bd.Token())
390+
}
391+
// TODO(elee1766): we don't enter another mapping here because it's annoying to extract the { and } properly.
392+
// maybe someone can do that in the future
393+
} else {
394+
// attempt to enter a block and add tokens to the currentMappingTokens
395+
for mappingNesting := bd.Nesting(); bd.NextBlock(mappingNesting); {
396+
currentMappingTokens = append(currentMappingTokens, bd.Token())
397+
}
398+
}
399+
blockMapping[currentMappingKey] = currentMappingTokens
400+
}
401+
}
402+
367403
// splice out the import directive and its arguments
368404
// (2 tokens, plus the length of args)
369-
tokensBefore := p.tokens[:p.cursor-1-len(args)]
405+
tokensBefore := p.tokens[:p.cursor-1-len(args)-len(blockTokens)]
370406
tokensAfter := p.tokens[p.cursor+1:]
371407
var importedTokens []Token
372408
var nodes []string
@@ -495,6 +531,33 @@ func (p *parser) doImport(nesting int) error {
495531
maybeSnippet = false
496532
}
497533
}
534+
// if it is {block}, we substitute with all tokens in the block
535+
// if it is {blocks.*}, we substitute with the tokens in the mapping for the *
536+
var skip bool
537+
var tokensToAdd []Token
538+
switch {
539+
case token.Text == "{block}":
540+
tokensToAdd = blockTokens
541+
case strings.HasPrefix(token.Text, "{blocks.") && strings.HasSuffix(token.Text, "}"):
542+
// {blocks.foo.bar} will be extracted to key `foo.bar`
543+
blockKey := strings.TrimPrefix(strings.TrimSuffix(token.Text, "}"), "{blocks.")
544+
val, ok := blockMapping[blockKey]
545+
if ok {
546+
tokensToAdd = val
547+
}
548+
default:
549+
skip = true
550+
}
551+
if !skip {
552+
if len(tokensToAdd) == 0 {
553+
// if there is no content in the snippet block, don't do any replacement
554+
// this allows snippets which contained {block}/{block.*} before this change to continue functioning as normal
555+
tokensCopy = append(tokensCopy, token)
556+
} else {
557+
tokensCopy = append(tokensCopy, tokensToAdd...)
558+
}
559+
continue
560+
}
498561

499562
if maybeSnippet {
500563
tokensCopy = append(tokensCopy, token)
@@ -516,7 +579,7 @@ func (p *parser) doImport(nesting int) error {
516579
// splice the imported tokens in the place of the import statement
517580
// and rewind cursor so Next() will land on first imported token
518581
p.tokens = append(tokensBefore, append(tokensCopy, tokensAfter...)...)
519-
p.cursor -= len(args) + 1
582+
p.cursor -= len(args) + len(blockTokens) + 1
520583

521584
return nil
522585
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
(snippet) {
2+
header {
3+
{block}
4+
}
5+
}
6+
7+
example.com {
8+
import snippet {
9+
foo bar
10+
}
11+
}
12+
----------
13+
{
14+
"apps": {
15+
"http": {
16+
"servers": {
17+
"srv0": {
18+
"listen": [
19+
":443"
20+
],
21+
"routes": [
22+
{
23+
"match": [
24+
{
25+
"host": [
26+
"example.com"
27+
]
28+
}
29+
],
30+
"handle": [
31+
{
32+
"handler": "subroute",
33+
"routes": [
34+
{
35+
"handle": [
36+
{
37+
"handler": "headers",
38+
"response": {
39+
"set": {
40+
"Foo": [
41+
"bar"
42+
]
43+
}
44+
}
45+
}
46+
]
47+
}
48+
]
49+
}
50+
],
51+
"terminal": true
52+
}
53+
]
54+
}
55+
}
56+
}
57+
}
58+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
(snippet) {
2+
{block}
3+
}
4+
5+
example.com {
6+
import snippet {
7+
header foo bar
8+
}
9+
}
10+
----------
11+
{
12+
"apps": {
13+
"http": {
14+
"servers": {
15+
"srv0": {
16+
"listen": [
17+
":443"
18+
],
19+
"routes": [
20+
{
21+
"match": [
22+
{
23+
"host": [
24+
"example.com"
25+
]
26+
}
27+
],
28+
"handle": [
29+
{
30+
"handler": "subroute",
31+
"routes": [
32+
{
33+
"handle": [
34+
{
35+
"handler": "headers",
36+
"response": {
37+
"set": {
38+
"Foo": [
39+
"bar"
40+
]
41+
}
42+
}
43+
}
44+
]
45+
}
46+
]
47+
}
48+
],
49+
"terminal": true
50+
}
51+
]
52+
}
53+
}
54+
}
55+
}
56+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
(snippet) {
2+
header {
3+
{blocks.foo}
4+
}
5+
header {
6+
{blocks.bar}
7+
}
8+
}
9+
10+
example.com {
11+
import snippet {
12+
foo {
13+
foo a
14+
}
15+
bar {
16+
bar b
17+
}
18+
}
19+
}
20+
----------
21+
{
22+
"apps": {
23+
"http": {
24+
"servers": {
25+
"srv0": {
26+
"listen": [
27+
":443"
28+
],
29+
"routes": [
30+
{
31+
"match": [
32+
{
33+
"host": [
34+
"example.com"
35+
]
36+
}
37+
],
38+
"handle": [
39+
{
40+
"handler": "subroute",
41+
"routes": [
42+
{
43+
"handle": [
44+
{
45+
"handler": "headers",
46+
"response": {
47+
"set": {
48+
"Foo": [
49+
"a"
50+
]
51+
}
52+
}
53+
},
54+
{
55+
"handler": "headers",
56+
"response": {
57+
"set": {
58+
"Bar": [
59+
"b"
60+
]
61+
}
62+
}
63+
}
64+
]
65+
}
66+
]
67+
}
68+
],
69+
"terminal": true
70+
}
71+
]
72+
}
73+
}
74+
}
75+
}
76+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
(snippet) {
2+
header {
3+
{blocks.bar}
4+
}
5+
import sub_snippet {
6+
bar {
7+
{blocks.foo}
8+
}
9+
}
10+
}
11+
(sub_snippet) {
12+
header {
13+
{blocks.bar}
14+
}
15+
}
16+
example.com {
17+
import snippet {
18+
foo {
19+
foo a
20+
}
21+
bar {
22+
bar b
23+
}
24+
}
25+
}
26+
----------
27+
{
28+
"apps": {
29+
"http": {
30+
"servers": {
31+
"srv0": {
32+
"listen": [
33+
":443"
34+
],
35+
"routes": [
36+
{
37+
"match": [
38+
{
39+
"host": [
40+
"example.com"
41+
]
42+
}
43+
],
44+
"handle": [
45+
{
46+
"handler": "subroute",
47+
"routes": [
48+
{
49+
"handle": [
50+
{
51+
"handler": "headers",
52+
"response": {
53+
"set": {
54+
"Bar": [
55+
"b"
56+
]
57+
}
58+
}
59+
},
60+
{
61+
"handler": "headers",
62+
"response": {
63+
"set": {
64+
"Foo": [
65+
"a"
66+
]
67+
}
68+
}
69+
}
70+
]
71+
}
72+
]
73+
}
74+
],
75+
"terminal": true
76+
}
77+
]
78+
}
79+
}
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)