Skip to content

Commit

Permalink
Impliment linter suggestions
Browse files Browse the repository at this point in the history
Fixed a ton of code style mistakes
Performed some light refactoring
  • Loading branch information
Andrew-Morozko committed Dec 21, 2023
1 parent 1ad825c commit e8b8855
Show file tree
Hide file tree
Showing 21 changed files with 329 additions and 224 deletions.
4 changes: 2 additions & 2 deletions cmd/plugins/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package main

import (
"github.com/hashicorp/go-plugin"

"github.com/blackstork-io/fabric/plugins"
"github.com/blackstork-io/fabric/plugins/content"
"github.com/blackstork-io/fabric/plugins/content/table"
"github.com/blackstork-io/fabric/plugins/content/text"
"github.com/blackstork-io/fabric/plugins/data"
"github.com/blackstork-io/fabric/plugins/data/plugin_a"
"github.com/blackstork-io/fabric/plugins/data/plugin_b"

"github.com/hashicorp/go-plugin"
)

func main() {
Expand Down
23 changes: 17 additions & 6 deletions decodeHcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ func (d *Decoder) DecodeBlock(block Block) (diag hcl.Diagnostics) {
leftover := extra.GetUnparsed()
attrs, attrDiags := leftover.JustAttributes()
if attrDiags.HasErrors() {
// TODO: messy hcl bug workaround, in some cases might silently ignore user's error
// FIXME: messy hcl bug workaround, fix pending approval https://github.com/hashicorp/hcl/pull/646
attrDiags = nil
body := leftover.(*hclsyntax.Body)
body, ok := leftover.(*hclsyntax.Body)
if !ok {
panic("leftover is always hclsyntax.Body!")
}
for _, b := range body.Blocks {
switch b.Type {
case "meta", "content":
Expand All @@ -77,7 +80,8 @@ func (d *Decoder) DecodeBlock(block Block) (diag hcl.Diagnostics) {
Severity: hcl.DiagWarning,
Summary: "Non-empty ref attribute",
Detail: fmt.Sprintf(
"Non-empty ref attribute found in block of type '%s'. It will be ignored. Block must have type 'ref' in order to use references",
"Non-empty ref attribute found in block of type '%s'. "+
"It will be ignored. Block must have type 'ref' in order to use references",
*block.GetType(),
),
Subject: extra.GetRef().Range().Ptr(),
Expand All @@ -91,7 +95,8 @@ func (d *Decoder) DecodeBlock(block Block) (diag hcl.Diagnostics) {
Severity: hcl.DiagWarning,
Summary: fmt.Sprintf("Unknown %s block type", block.GetBlockKind()),
Detail: fmt.Sprintf(
"Unknown content block type '%s', valid block types: %s. Referencing or evaluating this block would cause an error",
"Unknown content block type '%s', valid block types: %s. "+
"Referencing or evaluating this block would cause an error",
*block.GetType(),
plugins.Names(),
),
Expand All @@ -113,11 +118,17 @@ func (d *Decoder) DecodeBlock(block Block) (diag hcl.Diagnostics) {
}
if extra.GetRef().Range().Empty() {
missingRef.Summary = "Missing ref"
missingRef.Detail = fmt.Sprintf("Block '%s %s' is of type 'ref', but the ref field is missing", block.GetBlockKind(), block.GetName())
missingRef.Detail = fmt.Sprintf(
"Block '%s %s' is of type 'ref', but the ref field is missing",
block.GetBlockKind(), block.GetName(),
)
missingRef.Subject = block.GetUnparsed().MissingItemRange().Ptr()
} else {
missingRef.Summary = "Empty ref"
missingRef.Detail = fmt.Sprintf("Block '%s %s' is of type 'ref', but the ref field is empty", block.GetBlockKind(), block.GetName())
missingRef.Detail = fmt.Sprintf(
"Block '%s %s' is of type 'ref', but the ref field is empty",
block.GetBlockKind(), block.GetName(),
)
missingRef.Subject = extra.GetRef().Range().Ptr()
missingRef.Expression = extra.GetRef()
}
Expand Down
81 changes: 45 additions & 36 deletions evaluateBlocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ import (
"fmt"
"slices"
"strings"
"github.com/blackstork-io/fabric/pkg/diagnostics"
"github.com/blackstork-io/fabric/pkg/jsontools"
"github.com/blackstork-io/fabric/pkg/parexec"
"github.com/blackstork-io/fabric/plugins/content"
"github.com/blackstork-io/fabric/plugins/data"

"github.com/hashicorp/hcl/v2"
"github.com/itchyny/gojq"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/json"
"golang.org/x/exp/maps"

"github.com/blackstork-io/fabric/pkg/diagnostics"
"github.com/blackstork-io/fabric/pkg/jsontools"
"github.com/blackstork-io/fabric/pkg/parexec"
"github.com/blackstork-io/fabric/plugins/content"
"github.com/blackstork-io/fabric/plugins/data"
)

// TODO: define magic number
var limiter = parexec.NewLimiter(5) //nolint: gomnd

// data block evaluation

type dataBlocksEvaluator struct {
dataPlugins map[string]any
plugins map[string]any
}

type dataEvalResult struct {
diagnostics.Diagnostics
diagnostics.Diag
Type string
Name string
Res any
Expand All @@ -35,16 +39,16 @@ func (eb *dataBlocksEvaluator) evalBlock(db *DataBlock) (res dataEvalResult) {
res.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Undecoded block",
Detail: fmt.Sprintf(`%s block '%s %s "%s"' wasn't decoded`, BK_DATA, BK_DATA, db.Type, db.Name),
Detail: fmt.Sprintf(`%s block '%s %s "%s"' wasn't decoded`, DataBlockName, DataBlockName, db.Type, db.Name),
})
return
}
rawPlugin, found := eb.dataPlugins[db.Type]
rawPlugin, found := eb.plugins[db.Type]
if !found {
res.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Plugin not found",
Detail: fmt.Sprintf("plugin %s.%s not found", BK_DATA, db.Type),
Detail: fmt.Sprintf("plugin %s.%s not found", DataBlockName, db.Type),
})
return
}
Expand All @@ -56,7 +60,7 @@ func (eb *dataBlocksEvaluator) evalBlock(db *DataBlock) (res dataEvalResult) {

var err error
res.Res, err = rawPlugin.(data.Plugin).Execute(attrs)
if res.FromErr(err, "Data plugin error") {
if res.AppendErr(err, "Data plugin error") {
return
}

Expand All @@ -65,49 +69,50 @@ func (eb *dataBlocksEvaluator) evalBlock(db *DataBlock) (res dataEvalResult) {
return
}

func EvaluateDataBlocks(dataPlugins map[string]any, dataBlocks []DataBlock) (dict map[string]any, diags diagnostics.Diagnostics) {
func EvaluateDataBlocks(plugins map[string]any, dbs []DataBlock) (dict map[string]any, diags diagnostics.Diag) {
ev := dataBlocksEvaluator{
dataPlugins: dataPlugins,
plugins: plugins,
}
// access through pe lock
dataDict := map[string]any{}
pe := parexec.New(
parexec.NewLimiter(5),
limiter,
func(res dataEvalResult, _ int) (cmd parexec.Command) {
if diags.Extend(res.Diagnostics) {
return parexec.STOP
if diags.Extend(res.Diag) {
return parexec.CmdStop
}
var err error
dataDict, err = jsontools.MapSet(dataDict, []string{res.Type, res.Name}, res.Res)
diags.FromErr(err, "Data dict set key error")
diags.AppendErr(err, "Data dict set key error")
return
},
)
parexec.MapRef(pe, dataBlocks, ev.evalBlock)
parexec.MapRef(pe, dbs, ev.evalBlock)
pe.WaitDoneAndLock()
if diags.HasErrors() {
return
}
dict = map[string]any{
BK_DATA: dataDict,
DataBlockName: dataDict,
}
return
}

// content block queries

type queryEvaluator struct {
pe parexec.Executor[diagnostics.Diagnostics]
pe parexec.Executor[diagnostics.Diag]
dict map[string]any
goEvaluateQuery func(*ContentBlock)
}

func EvaluateQueries(dict map[string]any, cbs []ContentBlock) (diags diagnostics.Diagnostics) {
func EvaluateQueries(dict map[string]any, cbs []ContentBlock) (diags diagnostics.Diag) {
ev := queryEvaluator{
pe: *parexec.New(
parexec.NewLimiter(5),
func(res diagnostics.Diagnostics, idx int) (cmd parexec.Command) {
limiter,
func(res diagnostics.Diag, idx int) (cmd parexec.Command) {
if diags.Extend(res) {
return parexec.STOP
return parexec.CmdStop
}
return
},
Expand All @@ -133,7 +138,7 @@ func (ev *queryEvaluator) evaluateQueries(cbs []ContentBlock) {
}
}

func (ev *queryEvaluator) evaluateQuery(cb *ContentBlock) (diags diagnostics.Diagnostics) {
func (ev *queryEvaluator) evaluateQuery(cb *ContentBlock) (diags diagnostics.Diag) {
query, err := gojq.Parse(*cb.Query)
if err != nil {
diags.Append(&hcl.Diagnostic{
Expand Down Expand Up @@ -161,25 +166,26 @@ func (ev *queryEvaluator) evaluateQuery(cb *ContentBlock) (diags diagnostics.Dia
}

// content block queries

type contentBlocksEvaluator struct {
pe parexec.Executor[contentEvalResult]
contentPlugins map[string]any
goEvaluateContentBlock func(*ContentBlock)
}

type contentEvalResult struct {
diagnostics.Diagnostics
diagnostics.Diag
res string
}

func EvaluateContentBlocks(contentPlugins map[string]any, cbs []ContentBlock) (output string, diags diagnostics.Diagnostics) {
func EvaluateContentBlocks(contentPlugins map[string]any, cbs []ContentBlock) (output string, diags diagnostics.Diag) {
var orderedResult []string
ev := contentBlocksEvaluator{
pe: *parexec.New(
parexec.NewLimiter(5),
limiter,
func(res contentEvalResult, idx int) (cmd parexec.Command) {
if diags.Extend(res.Diagnostics) {
return parexec.STOP
if diags.Extend(res.Diag) {
return parexec.CmdStop
}
orderedResult = parexec.SetAt(orderedResult, idx, res.res)
return
Expand All @@ -202,7 +208,7 @@ func (ev *contentBlocksEvaluator) evaluateContentBlock(cb *ContentBlock) (res co
res.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Undecoded block",
Detail: fmt.Sprintf(`%s block '%s %s "%s"' wasn't decoded`, BK_DATA, BK_DATA, cb.Type, cb.Name),
Detail: fmt.Sprintf(`%s block '%s %s "%s"' wasn't decoded`, DataBlockName, DataBlockName, cb.Type, cb.Name),
})
return
}
Expand All @@ -211,7 +217,7 @@ func (ev *contentBlocksEvaluator) evaluateContentBlock(cb *ContentBlock) (res co
res.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Plugin not found",
Detail: fmt.Sprintf("plugin %s.%s not found", BK_DATA, cb.Type),
Detail: fmt.Sprintf("plugin %s.%s not found", DataBlockName, cb.Type),
})
return
}
Expand All @@ -221,7 +227,7 @@ func (ev *contentBlocksEvaluator) evaluateContentBlock(cb *ContentBlock) (res co
}

pluginRes, err := rawPlugin.(content.Plugin).Execute(attrs, cb.localDict)
if res.FromErr(err, "Content plugin error") {
if res.AppendErr(err, "Content plugin error") {
return
}
res.res = pluginRes
Expand All @@ -238,7 +244,7 @@ func (ev *contentBlocksEvaluator) evaluateContentBlocks(cbs []ContentBlock) {
}
}

func (d *Decoder) FindDoc(name string) (doc *Document, diags diagnostics.Diagnostics) {
func (d *Decoder) FindDoc(name string) (doc *Document, diags diagnostics.Diag) {
n := slices.IndexFunc(d.root.Documents, func(d Document) bool {
return d.Name == name
})
Expand All @@ -253,7 +259,7 @@ func (d *Decoder) FindDoc(name string) (doc *Document, diags diagnostics.Diagnos
return &d.root.Documents[n], nil
}

func (d *Decoder) Evaluate(name string) (output string, diags diagnostics.Diagnostics) {
func (d *Decoder) Evaluate(name string) (output string, diags diagnostics.Diag) {
doc, diag := d.FindDoc(name)
if diags.Extend(diag) {
return
Expand All @@ -275,6 +281,7 @@ func (d *Decoder) Evaluate(name string) (output string, diags diagnostics.Diagno

func AttrsToJSON(attrs hcl.Attributes) (res json.SimpleJSONValue, diag hcl.Diagnostics) {
attrsMap := make(map[string]cty.Value, len(attrs))

for key, attr := range attrs {
val, dgs := attr.Expr.Value(nil)
if len(dgs) > 0 {
Expand All @@ -283,9 +290,11 @@ func AttrsToJSON(attrs hcl.Attributes) (res json.SimpleJSONValue, diag hcl.Diagn
di.Detail = fmt.Sprintf("Evaluation failed for value at key '%s': %s", key, di.Detail)
}
diag = diag.Extend(dgs)

continue
}
attrsMap[key] = val
}
return json.SimpleJSONValue{Value: cty.ObjectVal(attrsMap)}, nil
res = json.SimpleJSONValue{Value: cty.ObjectVal(attrsMap)}
return
}
41 changes: 23 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,51 @@ package main
import (
"flag"
"fmt"

"os"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"

"github.com/blackstork-io/fabric/pkg/diagnostics"
)

// TODO: replace flag with a better parser (argparse).
var path, pluginPath, docName string

type Decoder struct {
root *Templates
plugins *Plugins
}

func argParse() error {
flag.StringVar(&path, "path", "", "a path to a directory with *.fabric files")
func argParse() (diags diagnostics.Diag) {
flag.StringVar(&path, "path", "", "a path to a directory with *.hcl files")
flag.StringVar(&pluginPath, "plugins", "", "a path to a __plugin file__")
flag.StringVar(&docName, "document", "", "the name of the document to process")
flag.Parse()
if path == "" {
return fmt.Errorf("path required")
diags.Add("Wrong usage", "path required")
}
if docName == "" {
return fmt.Errorf("document name required")
diags.Add("Wrong usage", "document name required")
}
if pluginPath == "" {
return fmt.Errorf("plugins required")
diags.Add("Wrong usage", "plugins required")
}
return nil
return
}

func run() error {
err := argParse()
if err != nil {
return err
}
body, fileMap, diags := fromDisk()
func run() (diags diagnostics.Diag) {
var fileMap map[string]*hcl.File
defer func() { PrintDiags(diags, fileMap) }()
if diags.HasErrors() {
return diags

diag := argParse()
if diags.Extend(diag) {
return
}

body, fileMap, diag := fromDisk()
if diags.Extend(diag) {
return
}

plugins, pluginDiag := NewPlugins(pluginPath)
Expand All @@ -67,13 +73,12 @@ func run() error {
if diag.HasErrors() {
return diags
}
fmt.Println(output)
fmt.Println(output) //nolint: forbidigo
return nil
}

func main() {
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err)
if diags := run(); diags.HasErrors() {
os.Exit(1)
}
}
Loading

0 comments on commit e8b8855

Please sign in to comment.