Skip to content

Commit

Permalink
Async data & content evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
dobarx committed Jan 3, 2025
1 parent a728b41 commit 6e18265
Show file tree
Hide file tree
Showing 21 changed files with 747 additions and 77 deletions.
42 changes: 42 additions & 0 deletions docs/plugins/builtin/content-providers/sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: "`sleep` content provider"
plugin:
name: blackstork/builtin
description: "Sleeps for the specified duration. Useful for testing and debugging"
tags: ["debug"]
version: "v0.4.2"
source_github: "https://github.com/blackstork-io/fabric/tree/main/internal/builtin/"
resource:
type: content-provider
type: docs
---

{{< breadcrumbs 2 >}}

{{< plugin-resource-header "blackstork/builtin" "builtin" "v0.4.2" "sleep" "content provider" >}}

## Description
Sleeps for the specified duration. Useful for testing and debugging.

The content provider is built-in, which means it's a part of `fabric` binary. It's available out-of-the-box, no installation required.


#### Configuration

The content provider doesn't support any configuration arguments.

#### Usage

The content provider supports the following execution arguments:

```hcl
content sleep {
# Duration to sleep
#
# Optional string.
# Must be non-empty
# Default value:
duration = "1s"
}
```

40 changes: 40 additions & 0 deletions docs/plugins/builtin/data-sources/sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: "`sleep` data source"
plugin:
name: blackstork/builtin
description: "Sleeps for the specified duration. Useful for testing and debugging"
tags: ["debug"]
version: "v0.4.2"
source_github: "https://github.com/blackstork-io/fabric/tree/main/internal/builtin/"
resource:
type: data-source
type: docs
---

{{< breadcrumbs 2 >}}

{{< plugin-resource-header "blackstork/builtin" "builtin" "v0.4.2" "sleep" "data source" >}}

## Description
Sleeps for the specified duration. Useful for testing and debugging.

The data source is built-in, which means it's a part of `fabric` binary. It's available out-of-the-box, no installation required.

## Configuration

The data source doesn't support any configuration arguments.

## Usage

The data source supports the following execution arguments:

```hcl
data sleep {
# Duration to sleep
#
# Optional string.
# Must be non-empty
# Default value:
duration = "1s"
}
```
14 changes: 14 additions & 0 deletions docs/plugins/plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@
"url"
]
},
{
"name": "sleep",
"type": "data-source",
"arguments": [
"duration"
]
},
{
"name": "sleep",
"type": "content-provider",
"arguments": [
"duration"
]
},
{
"name": "table",
"type": "content-provider",
Expand Down
12 changes: 7 additions & 5 deletions engine/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ type Options struct {
tracer trace.Tracer
}

var defaultLogger = slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{
Level: slog.LevelError,
}))

var defaultOptions = Options{
registryBaseURL: defaultRegistryBaseURL,
cacheDir: defaultCacheDir,
logger: slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{
Level: slog.LevelError,
})),
tracer: nooptrace.Tracer{},
builtin: builtin.Plugin("v0.0.0", nil, nil),
logger: defaultLogger,
tracer: nooptrace.Tracer{},
builtin: builtin.Plugin("v0.0.0", defaultLogger, nil),
}

type Option func(*Options)
Expand Down
74 changes: 12 additions & 62 deletions eval/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package eval
import (
"context"
"log/slog"
"maps"
"slices"

"github.com/hashicorp/hcl/v2"
Expand All @@ -25,33 +24,8 @@ type Document struct {
}

func (doc *Document) FetchData(ctx context.Context) (plugindata.Data, diagnostics.Diag) {
logger := *slog.Default()
logger.DebugContext(ctx, "Fetching data for the document template")
result := make(plugindata.Map)
diags := diagnostics.Diag{}
for _, block := range doc.DataBlocks {
var dsMap plugindata.Map
found, ok := result[block.PluginName]
if ok {
dsMap = found.(plugindata.Map)
} else {
dsMap = make(plugindata.Map)
result[block.PluginName] = dsMap
}
if _, found := dsMap[block.BlockName]; found {
diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Data conflict",
Detail: "Result of this block overwrites results from the previous invocation.",
Subject: &block.SrcRange,
})
}
dsMap[block.BlockName], diags = block.FetchData(ctx)
if diags.HasErrors() {
return nil, diags
}
}
return result, diags
evaluator := makeAsyncDataEvaluator(ctx, doc, slog.Default())
return evaluator.Execute()
}

func filterChildrenByTags(children []*Content, requiredTags []string) []*Content {
Expand All @@ -71,8 +45,8 @@ func filterChildrenByTags(children []*Content, requiredTags []string) []*Content
}

func (doc *Document) RenderContent(ctx context.Context, docDataCtx plugindata.Map, requiredTags []string) (*plugin.ContentSection, plugindata.Data, diagnostics.Diag) {
logger := *slog.Default()
logger.DebugContext(ctx, "Fetching data for the document template")
logger := slog.Default()
logger.WarnContext(ctx, "Render content for the document template", "document", doc.Source.Name)
data, diags := doc.FetchData(ctx)
if diags.HasErrors() {
return nil, nil, diags
Expand Down Expand Up @@ -110,40 +84,16 @@ func (doc *Document) RenderContent(ctx context.Context, docDataCtx plugindata.Ma
children = filterChildrenByTags(children, requiredTags)
}

result := plugin.NewSection(0)
// create a position map for content blocks
posMap := make(map[int]uint32, len(children))
for i := range children {
empty := new(plugin.ContentEmpty)
result.Add(empty, nil)
posMap[i] = empty.ID()
}
// sort content blocks by invocation order
invokeList := make([]int, 0, len(children))
for i := range children {
invokeList = append(invokeList, i)
evaluator, diag := makeAsyncContentEvaluator(ctx, children)
if diags.Extend(diag) {
return nil, nil, diags
}
slices.SortStableFunc(invokeList, func(a, b int) int {
ao := children[a].InvocationOrder()
bo := children[b].InvocationOrder()
return ao.Weight() - bo.Weight()
})
// execute content blocks based on the invocation order
for _, idx := range invokeList {
// clone the data context for each content block
dataCtx := maps.Clone(docDataCtx)
// set the current content to the data context
dataCtx[definitions.BlockKindDocument].(plugindata.Map)[definitions.BlockKindContent] = result.AsData()
// TODO: if section, set section

// execute the content block
diag := children[idx].RenderContent(ctx, dataCtx, result, result, posMap[idx])
if diags.Extend(diag) {
return nil, nil, diags
}

result, diag := evaluator.Execute(docDataCtx)
if diags.Extend(diag) {
return nil, nil, diags
}
// compact the content tree to remove empty content nodes
result.Compact()

return result, docDataCtx, diags
}

Expand Down
Loading

0 comments on commit 6e18265

Please sign in to comment.