Browse Source
This takes the config file as input and formats it. Prints the result to stdout. Can write changes to file if `--write` flag is passed. Fixes #3020 Signed-off-by: Vaibhav <vrongmeal@gmail.com>master
Vaibhav
5 years ago
committed by
GitHub
4 changed files with 346 additions and 0 deletions
@ -0,0 +1,137 @@ |
|||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|||
//
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
// you may not use this file except in compliance with the License.
|
|||
// You may obtain a copy of the License at
|
|||
//
|
|||
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
//
|
|||
// Unless required by applicable law or agreed to in writing, software
|
|||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
// See the License for the specific language governing permissions and
|
|||
// limitations under the License.
|
|||
|
|||
package caddyfile |
|||
|
|||
import ( |
|||
"bytes" |
|||
"io" |
|||
"unicode" |
|||
) |
|||
|
|||
// Format formats a Caddyfile to conventional standards.
|
|||
func Format(body []byte) []byte { |
|||
reader := bytes.NewReader(body) |
|||
result := new(bytes.Buffer) |
|||
|
|||
var ( |
|||
commented, |
|||
quoted, |
|||
escaped, |
|||
block, |
|||
environ, |
|||
lineBegin bool |
|||
|
|||
firstIteration = true |
|||
|
|||
prev, |
|||
curr, |
|||
next rune |
|||
|
|||
err error |
|||
) |
|||
|
|||
for { |
|||
prev = curr |
|||
curr = next |
|||
|
|||
if curr < 0 { |
|||
break |
|||
} |
|||
|
|||
next, _, err = reader.ReadRune() |
|||
if err != nil { |
|||
if err == io.EOF { |
|||
next = -1 |
|||
} else { |
|||
panic(err) |
|||
} |
|||
} |
|||
|
|||
if firstIteration { |
|||
firstIteration = false |
|||
lineBegin = true |
|||
continue |
|||
} |
|||
|
|||
if quoted { |
|||
if escaped { |
|||
escaped = false |
|||
} else { |
|||
if curr == '\\' { |
|||
escaped = true |
|||
} |
|||
if curr == '"' { |
|||
quoted = false |
|||
} |
|||
} |
|||
if curr == '\n' { |
|||
quoted = false |
|||
} |
|||
} else if commented { |
|||
if curr == '\n' { |
|||
commented = false |
|||
} |
|||
} else { |
|||
if curr == '"' { |
|||
quoted = true |
|||
} |
|||
if curr == '#' { |
|||
commented = true |
|||
} |
|||
if curr == '}' { |
|||
if environ { |
|||
environ = false |
|||
} else if block { |
|||
block = false |
|||
} |
|||
} |
|||
if curr == '{' { |
|||
if unicode.IsSpace(next) { |
|||
block = true |
|||
|
|||
if !unicode.IsSpace(prev) { |
|||
result.WriteRune(' ') |
|||
} |
|||
} else { |
|||
environ = true |
|||
} |
|||
} |
|||
if lineBegin { |
|||
if curr == ' ' || curr == '\t' { |
|||
continue |
|||
} else { |
|||
lineBegin = false |
|||
if block { |
|||
result.WriteRune('\t') |
|||
} |
|||
} |
|||
} else { |
|||
if prev == '{' && |
|||
(curr == ' ' || curr == '\t') && |
|||
(next != '\n' && next != '\r') { |
|||
curr = '\n' |
|||
} |
|||
} |
|||
} |
|||
|
|||
if curr == '\n' { |
|||
lineBegin = true |
|||
} |
|||
|
|||
result.WriteRune(curr) |
|||
} |
|||
|
|||
return result.Bytes() |
|||
} |
@ -0,0 +1,161 @@ |
|||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|||
//
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
// you may not use this file except in compliance with the License.
|
|||
// You may obtain a copy of the License at
|
|||
//
|
|||
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
//
|
|||
// Unless required by applicable law or agreed to in writing, software
|
|||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
// See the License for the specific language governing permissions and
|
|||
// limitations under the License.
|
|||
|
|||
package caddyfile |
|||
|
|||
import ( |
|||
"testing" |
|||
) |
|||
|
|||
func TestFormatBasicIndentation(t *testing.T) { |
|||
input := []byte(` |
|||
a |
|||
b |
|||
|
|||
c { |
|||
d |
|||
} |
|||
|
|||
e { f |
|||
} |
|||
`) |
|||
expected := []byte(` |
|||
a |
|||
b |
|||
|
|||
c { |
|||
d |
|||
} |
|||
|
|||
e { |
|||
f |
|||
} |
|||
`) |
|||
testFormat(t, input, expected) |
|||
} |
|||
|
|||
func TestFormatBasicSpacing(t *testing.T) { |
|||
input := []byte(` |
|||
a{ |
|||
b |
|||
} |
|||
|
|||
c{ d |
|||
} |
|||
`) |
|||
expected := []byte(` |
|||
a { |
|||
b |
|||
} |
|||
|
|||
c { |
|||
d |
|||
} |
|||
`) |
|||
testFormat(t, input, expected) |
|||
} |
|||
|
|||
func TestFormatEnvironmentVariable(t *testing.T) { |
|||
input := []byte(` |
|||
{$A} |
|||
|
|||
b { |
|||
{$C} |
|||
} |
|||
|
|||
d { {$E} |
|||
} |
|||
`) |
|||
expected := []byte(` |
|||
{$A} |
|||
|
|||
b { |
|||
{$C} |
|||
} |
|||
|
|||
d { |
|||
{$E} |
|||
} |
|||
`) |
|||
testFormat(t, input, expected) |
|||
} |
|||
|
|||
func TestFormatComments(t *testing.T) { |
|||
input := []byte(` |
|||
# a "\n" |
|||
|
|||
# b { |
|||
c |
|||
} |
|||
|
|||
d { |
|||
e # f |
|||
# g |
|||
} |
|||
|
|||
h { # i |
|||
} |
|||
`) |
|||
expected := []byte(` |
|||
# a "\n" |
|||
|
|||
# b { |
|||
c |
|||
} |
|||
|
|||
d { |
|||
e # f |
|||
# g |
|||
} |
|||
|
|||
h { |
|||
# i |
|||
} |
|||
`) |
|||
testFormat(t, input, expected) |
|||
} |
|||
|
|||
func TestFormatQuotesAndEscapes(t *testing.T) { |
|||
input := []byte(` |
|||
"a \"b\" #c |
|||
d |
|||
|
|||
e { |
|||
"f" |
|||
} |
|||
|
|||
g { "h" |
|||
} |
|||
`) |
|||
expected := []byte(` |
|||
"a \"b\" #c |
|||
d |
|||
|
|||
e { |
|||
"f" |
|||
} |
|||
|
|||
g { |
|||
"h" |
|||
} |
|||
`) |
|||
testFormat(t, input, expected) |
|||
} |
|||
|
|||
func testFormat(t *testing.T, input, expected []byte) { |
|||
output := Format(input) |
|||
if string(output) != string(expected) { |
|||
t.Errorf("Expected:\n%s\ngot:\n%s", string(output), string(expected)) |
|||
} |
|||
} |
Loading…
Reference in new issue