Skip to content

Commit

Permalink
feat: support reStructuredText
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaHoffmann committed Aug 8, 2022
1 parent 3cd4a9c commit 7dd1200
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 28 deletions.
20 changes: 16 additions & 4 deletions cli/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ func findBlocksInFile(fs afero.Fs, log *logrus.Logger, filename string, verbose,
ReadOnly: true,
LineRead: blocks.ReaderIgnore,
BlockWriter: blockWriter,
BlockRead: func(br *blocks.Reader, i int, b string) error {
BlockRead: func(br *blocks.Reader, i int, b string, preserveIndent bool) error {
if fmtverbs {
b = verbs.Escape(b)
}
Expand Down Expand Up @@ -433,7 +433,7 @@ func diffFile(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs, verbos
Log: log,
ReadOnly: true,
LineRead: blocks.ReaderPassthrough,
BlockRead: func(br *blocks.Reader, i int, b string) error {
BlockRead: func(br *blocks.Reader, i int, b string, preserveIndent bool) error {
var fb string
var err error
if fmtverbs {
Expand All @@ -445,6 +445,10 @@ func diffFile(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs, verbos
return err
}

if preserveIndent {
fb = indentToOriginalLevel(fb, b)
}

if fb == b {
return nil
}
Expand Down Expand Up @@ -500,7 +504,7 @@ func formatFile(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs, fixF
br := blocks.Reader{
Log: log,
LineRead: blocks.ReaderPassthrough,
BlockRead: func(br *blocks.Reader, i int, b string) error {
BlockRead: func(br *blocks.Reader, i int, b string, preserveIndent bool) error {
var fb string
var err error
if fmtverbs {
Expand All @@ -512,6 +516,10 @@ func formatFile(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs, fixF
return err
}

if preserveIndent {
fb = indentToOriginalLevel(fb, b)
}

hasChange := fb != b

if br.CurrentNodeCursor != nil {
Expand Down Expand Up @@ -574,7 +582,7 @@ func upgrade012File(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs,
br := blocks.Reader{
Log: log,
LineRead: blocks.ReaderPassthrough,
BlockRead: func(br *blocks.Reader, i int, b string) error {
BlockRead: func(br *blocks.Reader, i int, b string, preserveIndent bool) error {
var fb string
var err error
if fmtverbs {
Expand All @@ -586,6 +594,10 @@ func upgrade012File(fs afero.Fs, log *logrus.Logger, filename string, fmtverbs,
return err
}

if preserveIndent {
fb = indentToOriginalLevel(fb, b)
}

hasChange := fb != b

if br.CurrentNodeCursor != nil {
Expand Down
26 changes: 26 additions & 0 deletions cli/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cli

import (
"strings"
"unicode"
)

func indentToOriginalLevel(formatted string, original string) string {
prefix := ""
for _, r := range original {
if unicode.IsSpace(r) {
if r == '\n' {
prefix = ""
continue
}
prefix += string(r)
} else {
break
}
}
res := strings.ReplaceAll(formatted, "\n", "\n"+prefix)
res = strings.TrimRight(res, prefix)
res = strings.TrimLeft(res, prefix)

return prefix + res
}
38 changes: 15 additions & 23 deletions lib/blocks/blockreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"go/token"
"io"
"io/ioutil"
"path/filepath"
"regexp"
"strconv"
"strings"
Expand All @@ -21,7 +22,7 @@ import (

var lineWithLeadingSpacesMatcher = regexp.MustCompile("^[[:space:]]*(.*\n)$")

type blockReadFunc func(*Reader, int, string) error
type blockReadFunc func(*Reader, int, string, bool) error

type BlockWriter interface {
Write(index, startLine, endLine int, text string)
Expand Down Expand Up @@ -71,23 +72,6 @@ func ReaderIgnore(br *Reader, number int, line string) error {
return nil
}

func IsStartLine(line string) bool {
// nolint:gocritic
if strings.HasPrefix(line, "```hcl") { // documentation
return true
} else if strings.HasPrefix(line, "```terraform") { // documentation
return true
} else if strings.HasPrefix(line, "```tf") { // documentation
return true
}

return false
}

func IsFinishLine(line string) bool {
return strings.HasPrefix(line, "```") // documentation
}

type blockVisitor struct {
br *Reader
fset *token.FileSet
Expand Down Expand Up @@ -116,7 +100,7 @@ func (bv blockVisitor) Visit(cursor *astutil.Cursor) bool {
// This is to deal with some outputs using just LineCount and some using LineCount-BlockCurrentLine
bv.br.BlockCurrentLine = bv.fset.Position(node.End()).Line - bv.fset.Position(node.Pos()).Line

err := bv.f(bv.br, 0, value)
err := bv.f(bv.br, 0, value, false)
if err != nil {
bv.br.ErrorBlocks++
bv.br.Log.Errorf("block %d @ %s:%d failed to process with: %v", bv.br.BlockCount, bv.br.FileName, bv.fset.Position(node.Pos()).Line, err)
Expand Down Expand Up @@ -256,6 +240,14 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
}
}

var format textFormat
switch filepath.Ext(filename) {
case ".rst":
format = restructuredTextFormat{}
default:
format = markdownTextFormat{}
}

br.LineCount = 0
br.BlockCount = 0
s := bufio.NewScanner(br.Reader)
Expand All @@ -268,7 +260,7 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
return fmt.Errorf("NB LineRead failed @ %s:%d for %s: %w", br.FileName, br.LineCount, l, err)
}

if IsStartLine(l) {
if format.isStartingLine(l) {
block := ""
br.BlockCurrentLine = 0
br.BlockCount++
Expand All @@ -279,7 +271,7 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
l2 := s.Text() + "\n"

// make sure we don't run into another block
if IsStartLine(l2) {
if format.isStartingLine(l2) {
// the end of current block must be malformed, so lets pass it through and log an error
br.Log.Errorf("block %d @ %s:%d failed to find end of block", br.BlockCount, br.FileName, br.LineCount-br.BlockCurrentLine)
if err := ReaderPassthrough(br, br.LineCount, block); err != nil { // is this ok or should we loop with LineRead?
Expand All @@ -296,15 +288,15 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
continue
}

if IsFinishLine(l2) {
if format.isFinishLine(l2) {
if br.FixFinishLines {
l2 = lineWithLeadingSpacesMatcher.ReplaceAllString(l2, `$1`)
}

br.LinesBlock += br.BlockCurrentLine

// todo configure this behaviour with switch's
if err := br.BlockRead(br, br.LineCount, block); err != nil {
if err := br.BlockRead(br, br.LineCount, block, format.preserveIndentation()); err != nil {
// for now ignore block errors and output unformatted
br.ErrorBlocks++
br.Log.Errorf("block %d @ %s:%d failed to process with: %v", br.BlockCount, br.FileName, br.LineCount-br.BlockCurrentLine, err)
Expand Down
112 changes: 111 additions & 1 deletion lib/blocks/blockreader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,116 @@ func TestBlockDetection(t *testing.T) {
resource "aws_s3_bucket" "leading-space-and-line" {
bucket = "tf-test-bucket-leading-space-and-line"
}
`,
},
},
},
{
sourcefile: "testdata/test3.rst",
expectedBlocks: []block{
{
text: ` resource "aws_s3_bucket" "terraform" {
bucket = "tf-test-bucket-terraform"
}
`,
},
{
text: ` resource "azurerm_resource_group" "example" {
name = "testaccbatch"
location = "West Europe"
}
resource "azurerm_storage_account" "example" {
name = "testaccsa"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_batch_account" "example" {
name = "testaccbatch"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
pool_allocation_mode = "BatchService"
storage_account_id = azurerm_storage_account.example.id
tags = {
env = "test"
}
}
resource "azurerm_batch_certificate" "example" {
resource_group_name = azurerm_resource_group.example.name
account_name = azurerm_batch_account.example.name
certificate = filebase64("certificate.cer")
format = "Cer"
thumbprint = "312d31a79fa0cef49c00f769afc2b73e9f4edf34"
thumbprint_algorithm = "SHA1"
}
resource "azurerm_batch_pool" "example" {
name = "testaccpool"
resource_group_name = azurerm_resource_group.example.name
account_name = azurerm_batch_account.example.name
display_name = "Test Acc Pool Auto"
vm_size = "Standard_A1"
node_agent_sku_id = "batch.node.ubuntu 20.04"
auto_scale {
evaluation_interval = "PT15M"
formula = <<EOF
startingNumberOfVMs = 1;
maxNumberofVMs = 25;
pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(180 * TimeInterval_Second);
pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(180 * TimeInterval_Second));
$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);
EOF
}
storage_image_reference {
publisher = "microsoft-azure-batch"
offer = "ubuntu-server-container"
sku = "20-04-lts"
version = "latest"
}
container_configuration {
type = "DockerCompatible"
container_registries {
registry_server = "docker.io"
user_name = "login"
password = "apassword"
}
}
start_task {
command_line = "echo 'Hello World from $env'"
task_retry_maximum = 1
wait_for_success = true
common_environment_properties = {
env = "TEST"
}
user_identity {
auto_user {
elevation_level = "NonAdmin"
scope = "Task"
}
}
}
certificate {
id = azurerm_batch_certificate.example.id
store_location = "CurrentUser"
visibility = ["StartTask"]
}
}
`,
},
},
Expand All @@ -138,7 +248,7 @@ func TestBlockDetection(t *testing.T) {
Log: log,
ReadOnly: true,
LineRead: ReaderIgnore,
BlockRead: func(br *Reader, i int, b string) error {
BlockRead: func(br *Reader, i int, b string, preserveIndent bool) error {
actualBlocks = append(actualBlocks, block{
leadingPadding: br.CurrentNodeLeadingPadding,
text: b,
Expand Down
Loading

0 comments on commit 7dd1200

Please sign in to comment.