mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 22:23:48 +03:00
caddyfile: Add args on imports (#3423)
* caddyfile: Add support for args on imports * caddyfile: Add more import args tests
This commit is contained in:
parent
a496308f6e
commit
fdf2a77feb
7 changed files with 168 additions and 8 deletions
|
@ -20,7 +20,10 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses the input just enough to group tokens, in
|
// Parse parses the input just enough to group tokens, in
|
||||||
|
@ -292,11 +295,19 @@ func (p *parser) doImport() error {
|
||||||
if importPattern == "" {
|
if importPattern == "" {
|
||||||
return p.Err("Import requires a non-empty filepath")
|
return p.Err("Import requires a non-empty filepath")
|
||||||
}
|
}
|
||||||
if p.NextArg() {
|
|
||||||
return p.Err("Import takes only one argument (glob pattern or file)")
|
// grab remaining args as placeholder replacements
|
||||||
|
args := p.RemainingArgs()
|
||||||
|
|
||||||
|
// add args to the replacer
|
||||||
|
repl := caddy.NewReplacer()
|
||||||
|
for index, arg := range args {
|
||||||
|
repl.Set("args."+strconv.Itoa(index), arg)
|
||||||
}
|
}
|
||||||
// splice out the import directive and its argument (2 tokens total)
|
|
||||||
tokensBefore := p.tokens[:p.cursor-1]
|
// splice out the import directive and its arguments
|
||||||
|
// (2 tokens, plus the length of args)
|
||||||
|
tokensBefore := p.tokens[:p.cursor-1-len(args)]
|
||||||
tokensAfter := p.tokens[p.cursor+1:]
|
tokensAfter := p.tokens[p.cursor+1:]
|
||||||
var importedTokens []Token
|
var importedTokens []Token
|
||||||
|
|
||||||
|
@ -348,10 +359,20 @@ func (p *parser) doImport() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy the tokens so we don't overwrite p.definedSnippets
|
||||||
|
tokensCopy := make([]Token, len(importedTokens))
|
||||||
|
copy(tokensCopy, importedTokens)
|
||||||
|
|
||||||
|
// run the argument replacer on the tokens
|
||||||
|
for index, token := range tokensCopy {
|
||||||
|
token.Text = repl.ReplaceKnown(token.Text, "")
|
||||||
|
tokensCopy[index] = token
|
||||||
|
}
|
||||||
|
|
||||||
// splice the imported tokens in the place of the import statement
|
// splice the imported tokens in the place of the import statement
|
||||||
// and rewind cursor so Next() will land on first imported token
|
// and rewind cursor so Next() will land on first imported token
|
||||||
p.tokens = append(tokensBefore, append(importedTokens, tokensAfter...)...)
|
p.tokens = append(tokensBefore, append(tokensCopy, tokensAfter...)...)
|
||||||
p.cursor--
|
p.cursor -= len(args) + 1
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,14 +182,17 @@ func TestParseOneAndImport(t *testing.T) {
|
||||||
"host1",
|
"host1",
|
||||||
}, []int{1, 2}},
|
}, []int{1, 2}},
|
||||||
|
|
||||||
{`import testdata/import_test1.txt testdata/import_test2.txt`, true, []string{}, []int{}},
|
|
||||||
|
|
||||||
{`import testdata/not_found.txt`, true, []string{}, []int{}},
|
{`import testdata/not_found.txt`, true, []string{}, []int{}},
|
||||||
|
|
||||||
{`""`, false, []string{}, []int{}},
|
{`""`, false, []string{}, []int{}},
|
||||||
|
|
||||||
{``, false, []string{}, []int{}},
|
{``, false, []string{}, []int{}},
|
||||||
|
|
||||||
|
// import with args
|
||||||
|
{`import testdata/import_args0.txt a`, false, []string{"a"}, []int{}},
|
||||||
|
{`import testdata/import_args1.txt a b`, false, []string{"a", "b"}, []int{}},
|
||||||
|
{`import testdata/import_args*.txt a b`, false, []string{"a"}, []int{2}},
|
||||||
|
|
||||||
// test cases found by fuzzing!
|
// test cases found by fuzzing!
|
||||||
{`import }{$"`, true, []string{}, []int{}},
|
{`import }{$"`, true, []string{}, []int{}},
|
||||||
{`import /*/*.txt`, true, []string{}, []int{}},
|
{`import /*/*.txt`, true, []string{}, []int{}},
|
||||||
|
@ -210,6 +213,7 @@ func TestParseOneAndImport(t *testing.T) {
|
||||||
t.Errorf("Test %d: Expected no error, but got: %v", i, err)
|
t.Errorf("Test %d: Expected no error, but got: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t.Logf("%+v\n", result)
|
||||||
if len(result.Keys) != len(test.keys) {
|
if len(result.Keys) != len(test.keys) {
|
||||||
t.Errorf("Test %d: Expected %d keys, got %d",
|
t.Errorf("Test %d: Expected %d keys, got %d",
|
||||||
i, len(test.keys), len(result.Keys))
|
i, len(test.keys), len(result.Keys))
|
||||||
|
|
1
caddyconfig/caddyfile/testdata/import_args0.txt
vendored
Normal file
1
caddyconfig/caddyfile/testdata/import_args0.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{args.0}
|
1
caddyconfig/caddyfile/testdata/import_args1.txt
vendored
Normal file
1
caddyconfig/caddyfile/testdata/import_args1.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{args.0} {args.1}
|
49
caddytest/integration/caddyfile_adapt/import_args_file.txt
Normal file
49
caddytest/integration/caddyfile_adapt/import_args_file.txt
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
example.com
|
||||||
|
|
||||||
|
import testdata/import_respond.txt Groot Rocket
|
||||||
|
import testdata/import_respond.txt you "the confused man"
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"body": "'I am Groot', hears Rocket",
|
||||||
|
"handler": "static_response"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"body": "'I am you', hears the confused man",
|
||||||
|
"handler": "static_response"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
(logging) {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/{args.0}.access.log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.example.com {
|
||||||
|
import logging a.example.com
|
||||||
|
}
|
||||||
|
|
||||||
|
b.example.com {
|
||||||
|
import logging b.example.com
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"logging": {
|
||||||
|
"logs": {
|
||||||
|
"default": {
|
||||||
|
"exclude": [
|
||||||
|
"http.log.access.log0",
|
||||||
|
"http.log.access.log1"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"log0": {
|
||||||
|
"writer": {
|
||||||
|
"filename": "/var/log/caddy/a.example.com.access.log",
|
||||||
|
"output": "file"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"http.log.access.log0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"log1": {
|
||||||
|
"writer": {
|
||||||
|
"filename": "/var/log/caddy/b.example.com.access.log",
|
||||||
|
"output": "file"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"http.log.access.log1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"a.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"b.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"logs": {
|
||||||
|
"logger_names": {
|
||||||
|
"a.example.com": "log0",
|
||||||
|
"b.example.com": "log1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
caddytest/integration/testdata/import_respond.txt
vendored
Normal file
1
caddytest/integration/testdata/import_respond.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
respond "'I am {args.0}', hears {args.1}"
|
Loading…
Reference in a new issue