Skip to content

Commit

Permalink
✨ refactor providers coordinator (#3308)
Browse files Browse the repository at this point in the history
* ✨ shutdown any unused providers on runtime.Close

Signed-off-by: Ivan Milchev <[email protected]>

* add a Coordinator interface to allow mocking

Signed-off-by: Ivan Milchev <[email protected]>

* use uber mockgen instead of golang mockgen

Signed-off-by: Ivan Milchev <[email protected]>

* cleanup coordinator code

Signed-off-by: Ivan Milchev <[email protected]>

* fix makefile and gitignore

Signed-off-by: Ivan Milchev <[email protected]>

* remove Stop function from coordinator interface

Signed-off-by: Ivan Milchev <[email protected]>

* fix gh actions

Signed-off-by: Ivan Milchev <[email protected]>

* fix deadlock

Signed-off-by: Ivan Milchev <[email protected]>

* add mocks for plugins

Signed-off-by: Ivan Milchev <[email protected]>

* add more tests

Signed-off-by: Ivan Milchev <[email protected]>

* refactor mock generation

Signed-off-by: Ivan Milchev <[email protected]>

* fix tests

Signed-off-by: Ivan Milchev <[email protected]>

* add more tests

Signed-off-by: Ivan Milchev <[email protected]>

* remove unused var

Signed-off-by: Ivan Milchev <[email protected]>

* fix go.mod formatting

Signed-off-by: Ivan Milchev <[email protected]>

* lock for the whole call of GetRunningProvider

Signed-off-by: Ivan Milchev <[email protected]>

* 🧹 use 1 global resource schema instead of per runtime (#3326)

* use uber mockgen instead of golang mockgen

Signed-off-by: Ivan Milchev <[email protected]>

* fix go.mod formatting

Signed-off-by: Ivan Milchev <[email protected]>

* 🧹 use 1 global resource schema instead of per runtime

Signed-off-by: Ivan Milchev <[email protected]>

* fix tests

Signed-off-by: Ivan Milchev <[email protected]>

* fix more tests

Signed-off-by: Ivan Milchev <[email protected]>

* make sure resource overriding and extension works

Signed-off-by: Ivan Milchev <[email protected]>

* fix tests

Signed-off-by: Ivan Milchev <[email protected]>

* fix more failing tests

Signed-off-by: Ivan Milchev <[email protected]>

* code cleanup

Signed-off-by: Ivan Milchev <[email protected]>

* more test fixes

Signed-off-by: Ivan Milchev <[email protected]>

* more fixes

Signed-off-by: Ivan Milchev <[email protected]>

* fix extensible schema test

Signed-off-by: Ivan Milchev <[email protected]>

* add more safe guards for merging resources

Signed-off-by: Ivan Milchev <[email protected]>

* make extensible schema test deterministic

Signed-off-by: Ivan Milchev <[email protected]>

* fix comments

Signed-off-by: Ivan Milchev <[email protected]>

* fix linter

Signed-off-by: Ivan Milchev <[email protected]>

---------

Signed-off-by: Ivan Milchev <[email protected]>

* code cleanup

Signed-off-by: Ivan Milchev <[email protected]>

---------

Signed-off-by: Ivan Milchev <[email protected]>
  • Loading branch information
imilchev authored Feb 19, 2024
1 parent 1be4e31 commit 7d1f8a5
Show file tree
Hide file tree
Showing 34 changed files with 824 additions and 419 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/pr-extended-linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
with:
go-version: ">=${{ env.golang-version }}"
cache: false
- name: Generate test files
run: make test/generate
- name: Run golangci-lint
uses: golangci/[email protected]
with:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/pr-test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:

- run: make providers/build/core

- run: make test/generate

- name: Run protolint
run: make test/lint/proto

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ providers/*.resources.json
providers/*/dist
providers/*/resources/*.resources.json
providers/*/resources/*.manifest.json
providers/mock_coordinator.go
providers/mock_plugin_interface.go
providers-sdk/*/testutils/mockprovider/resources/*.resources.json
!providers/core/resources/*.resources.json
23 changes: 14 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,18 @@ prep/tools/protolint:
# protobuf linting
go install github.com/yoheimuta/protolint/cmd/protolint@latest

prep/tools: prep/tools/protolint
# protobuf tooling
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install go.mondoo.com/ranger-rpc/protoc-gen-rangerrpc@latest
go install go.mondoo.com/ranger-rpc/protoc-gen-rangerrpc-swagger@latest
prep/tools: prep/tools/protolint prep/tools/mockgen
# additional helper
go install gotest.tools/gotestsum@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/hashicorp/copywrite@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install go.mondoo.com/ranger-rpc/protoc-gen-rangerrpc@latest
go install go.mondoo.com/ranger-rpc/protoc-gen-rangerrpc-swagger@latest

prep/tools/mockgen:
go install go.uber.org/mock/mockgen@latest

# 🌙 MQL/MOTOR #

Expand Down Expand Up @@ -597,18 +599,21 @@ test: test/go test/lint
benchmark/go:
go test -bench=. -benchmem go.mondoo.com/cnquery/v10/explorer/scan/benchmark

test/go: cnquery/generate test/go/plain
test/generate: prep/tools/mockgen
go generate ./providers

test/go: cnquery/generate test/generate test/go/plain

test/go/plain:
go test -cover $(shell go list ./... | grep -v '/providers/' | grep -v '/test/cli')

test/go/plain-ci: prep/tools providers/build
test/go/plain-ci: prep/tools test/generate providers/build
gotestsum --junitfile report.xml --format pkgname -- -cover $(shell go list ./... | grep -v '/vendor/' | grep -v '/providers/' | grep -v '/test/cli')

test/go-cli/plain:
go test -cover $(shell go list ./... | grep 'test/cli')

test/go-cli/plain-ci: prep/tools providers/build
test/go-cli/plain-ci: prep/tools test/generate providers/build
gotestsum --junitfile report.xml --format pkgname -- -cover $(shell go list ./... | grep 'test/cli')

.PHONY: test/lint/staticcheck
Expand Down
4 changes: 2 additions & 2 deletions apps/cnquery/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var rootCmd = &cobra.Command{
Short: "cnquery CLI",
Long: theme.DefaultTheme.Landing + "\n\n" + rootCmdDesc,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initLogger(cmd)
initLogger()
},
}

Expand Down Expand Up @@ -122,7 +122,7 @@ func init() {
config.Init(rootCmd)
}

func initLogger(cmd *cobra.Command) {
func initLogger() {
// environment variables always over-write custom flags
envLevel, ok := logger.GetEnvLogLevel()
if ok {
Expand Down
6 changes: 3 additions & 3 deletions cli/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"github.com/muesli/termenv"
"go.mondoo.com/cnquery/v10/cli/theme/colors"
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
)

// Printer turns code into human-readable strings
Expand All @@ -23,7 +23,7 @@ type Printer struct {
Disabled func(...interface{}) string
Failed func(...interface{}) string
Success func(...interface{}) string
schema llx.Schema
schema resources.ResourcesSchema
}

// DefaultPrinter that can be used without additional configuration
Expand Down Expand Up @@ -54,7 +54,7 @@ var DefaultPrinter = Printer{
},
}

func (p *Printer) SetSchema(schema llx.Schema) {
func (p *Printer) SetSchema(schema resources.ResourcesSchema) {
p.schema = schema
}

Expand Down
6 changes: 3 additions & 3 deletions cli/shell/completer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ package shell
import (
"github.com/c-bata/go-prompt"
"go.mondoo.com/cnquery/v10"
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/mqlc"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
)

var completerSeparator = string([]byte{'.', ' '})

// Completer is an auto-complete helper for the shell
type Completer struct {
schema llx.Schema
schema resources.ResourcesSchema
features cnquery.Features
queryPrefix func() string
}

// NewCompleter creates a new Mondoo completer object
func NewCompleter(schema llx.Schema, features cnquery.Features, queryPrefix func() string) *Completer {
func NewCompleter(schema resources.ResourcesSchema, features cnquery.Features, queryPrefix func() string) *Completer {
return &Completer{
schema: schema,
features: features,
Expand Down
4 changes: 2 additions & 2 deletions explorer/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
"github.com/segmentio/ksuid"
"go.mondoo.com/cnquery/v10"
"go.mondoo.com/cnquery/v10/checksums"
llx "go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/mqlc"
"go.mondoo.com/cnquery/v10/mrn"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
"go.mondoo.com/cnquery/v10/utils/multierr"
"sigs.k8s.io/yaml"
)
Expand Down Expand Up @@ -212,7 +212,7 @@ func (p *Bundle) AddBundle(other *Bundle) error {
}

// Compile a bundle. See CompileExt for a full description.
func (p *Bundle) Compile(ctx context.Context, schema llx.Schema) (*BundleMap, error) {
func (p *Bundle) Compile(ctx context.Context, schema resources.ResourcesSchema) (*BundleMap, error) {
return p.CompileExt(ctx, BundleCompileConf{
CompilerConfig: mqlc.NewConfig(schema, cnquery.DefaultFeatures),
})
Expand Down
2 changes: 1 addition & 1 deletion explorer/executor/mustcompile.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func MustCompile(code string) *llx.CodeBundle {
codeBundle, err := mqlc.Compile(code, nil,
mqlc.NewConfig(providers.DefaultRuntime().Schema(), cnquery.DefaultFeatures))
mqlc.NewConfig(providers.Coordinator.Schema(), cnquery.DefaultFeatures))
if err != nil {
panic(err)
}
Expand Down
3 changes: 2 additions & 1 deletion explorer/query_conductor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
llx "go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/mqlc"
"go.mondoo.com/cnquery/v10/mrn"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
"go.mondoo.com/cnquery/v10/utils/multierr"
"go.mondoo.com/ranger-rpc/codes"
"go.mondoo.com/ranger-rpc/status"
Expand Down Expand Up @@ -279,7 +280,7 @@ func (s *LocalServices) addQueryToJob(ctx context.Context, query *Mquery, job *E

// MatchFilters will take the list of filters and only return the ones
// that are supported by the given querypacks.
func MatchFilters(entityMrn string, filters []*Mquery, packs []*QueryPack, schema llx.Schema) (string, error) {
func MatchFilters(entityMrn string, filters []*Mquery, packs []*QueryPack, schema resources.ResourcesSchema) (string, error) {
supported := map[string]*Mquery{}
for i := range packs {
pack := packs[i]
Expand Down
4 changes: 2 additions & 2 deletions explorer/scan/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

"go.mondoo.com/cnquery/v10"
"go.mondoo.com/cnquery/v10/explorer"
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
"go.mondoo.com/cnquery/v10/utils/multierr"
)

Expand All @@ -25,7 +25,7 @@ func newFetcher() *fetcher {
}
}

func (f *fetcher) fetchBundles(ctx context.Context, schema llx.Schema, urls ...string) (*explorer.Bundle, error) {
func (f *fetcher) fetchBundles(ctx context.Context, schema resources.ResourcesSchema, urls ...string) (*explorer.Bundle, error) {
var res *explorer.Bundle = &explorer.Bundle{}

for i := range urls {
Expand Down
3 changes: 0 additions & 3 deletions explorer/scan/local_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,6 @@ func CreateProgressBar(discoveredAssets *DiscoveredAssets, disableProgressBar bo
func (s *LocalScanner) distributeJob(job *Job, ctx context.Context, upstream *upstream.UpstreamConfig) (*explorer.ReportCollection, error) {
log.Info().Msgf("discover related assets for %d asset(s)", len(job.Inventory.Spec.Assets))

// Always shut down the coordinator, to make sure providers are killed
defer providers.Coordinator.Shutdown()

discoveredAssets, err := DiscoverAssets(ctx, job.Inventory, upstream, s.recording)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ require (
github.com/gobwas/glob v0.2.3
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/golang/mock v1.6.0
github.com/golangci/golangci-lint v1.56.2
github.com/google/go-cmdtest v0.4.0
github.com/google/go-cmp v0.6.0
Expand Down Expand Up @@ -180,6 +179,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect
go.opentelemetry.io/otel/metric v1.23.1 // indirect
go.opentelemetry.io/otel/sdk v1.22.0 // indirect
go.uber.org/mock v0.4.0
gopkg.in/warnings.v0 v0.1.2 // indirect
gotest.tools/v3 v3.5.1 // indirect
)
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -1203,6 +1202,8 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
Expand Down
8 changes: 1 addition & 7 deletions llx/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,12 @@ type Runtime interface {
CreateResource(name string, args map[string]*Primitive) (Resource, error)
CloneResource(src Resource, id string, fields []string, args map[string]*Primitive) (Resource, error)
WatchAndUpdate(resource Resource, field string, watcherUID string, callback func(res interface{}, err error)) error
Schema() Schema
Schema() resources.ResourcesSchema
Close()
Recording() Recording
SetRecording(recording Recording) error
}

type Schema interface {
Lookup(resource string) *resources.ResourceInfo
LookupField(resource string, field string) (*resources.ResourceInfo, *resources.Field)
AllResources() map[string]*resources.ResourceInfo
}

type Recording interface {
Save() error
EnsureAsset(asset *inventory.Asset, provider string, connectionID uint32, conf *inventory.Config)
Expand Down
3 changes: 2 additions & 1 deletion mql/internal/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v10"
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
)

type query struct {
Expand Down Expand Up @@ -102,7 +103,7 @@ func (b *GraphBuilder) WithFeatureBoolAssertions(featureBoolAssertions bool) {
b.featureBoolAssertions = featureBoolAssertions
}

func (b *GraphBuilder) Build(schema llx.Schema, runtime llx.Runtime, assetMrn string) (*GraphExecutor, error) {
func (b *GraphBuilder) Build(schema resources.ResourcesSchema, runtime llx.Runtime, assetMrn string) (*GraphExecutor, error) {
resultChan := make(chan *llx.RawResult, 128)

queries := make(map[string]query, len(b.queries))
Expand Down
5 changes: 3 additions & 2 deletions mql/internal/execution_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
)

type executionManager struct {
schema llx.Schema
schema resources.ResourcesSchema
runtime llx.Runtime
// runQueue is the channel the execution manager will read
// items that need to be run from
Expand All @@ -37,7 +38,7 @@ type runQueueItem struct {
props map[string]*llx.Result
}

func newExecutionManager(schema llx.Schema, runtime llx.Runtime, runQueue chan runQueueItem,
func newExecutionManager(schema resources.ResourcesSchema, runtime llx.Runtime, runQueue chan runQueueItem,
resultChan chan *llx.RawResult, timeout time.Duration,
) *executionManager {
return &executionManager{
Expand Down
7 changes: 4 additions & 3 deletions mqlc/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import (
"strconv"

"go.mondoo.com/cnquery/v10/llx"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/resources"
"go.mondoo.com/cnquery/v10/types"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)

func createLabel(res *llx.CodeBundle, ref uint64, schema llx.Schema) (string, error) {
func createLabel(res *llx.CodeBundle, ref uint64, schema resources.ResourcesSchema) (string, error) {
code := res.CodeV2
chunk := code.Chunk(ref)

Expand Down Expand Up @@ -129,7 +130,7 @@ func stripCtlAndExtFromUnicode(str string) string {
}

// UpdateLabels for the given code under the schema
func UpdateLabels(res *llx.CodeBundle, schema llx.Schema) error {
func UpdateLabels(res *llx.CodeBundle, schema resources.ResourcesSchema) error {
if res == nil || res.CodeV2 == nil {
return errors.New("cannot create labels without code")
}
Expand All @@ -147,7 +148,7 @@ func UpdateLabels(res *llx.CodeBundle, schema llx.Schema) error {
return nil
}

func updateLabels(res *llx.CodeBundle, block *llx.Block, schema llx.Schema) error {
func updateLabels(res *llx.CodeBundle, block *llx.Block, schema resources.ResourcesSchema) error {
datapoints := block.Datapoints
code := res.CodeV2
labels := res.Labels.Labels
Expand Down
11 changes: 5 additions & 6 deletions mqlc/mqlc.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (vm *varmap) len() int {
}

type CompilerConfig struct {
Schema llx.Schema
Schema resources.ResourcesSchema
UseAssetContext bool
Stats CompilerStats
}
Expand All @@ -100,7 +100,7 @@ func (c *CompilerConfig) EnableMultiStats() {
c.Stats = newCompilerMultiStats()
}

func NewConfig(schema llx.Schema, features cnquery.Features) CompilerConfig {
func NewConfig(schema resources.ResourcesSchema, features cnquery.Features) CompilerConfig {
return CompilerConfig{
Schema: schema,
UseAssetContext: features.IsActive(cnquery.MQLAssetContext),
Expand Down Expand Up @@ -203,7 +203,7 @@ func findFuzzy(name string, names []string) fuzzy.Ranks {
return suggested
}

func addResourceSuggestions(schema llx.Schema, name string, res *llx.CodeBundle) {
func addResourceSuggestions(schema resources.ResourcesSchema, name string, res *llx.CodeBundle) {
resourceInfos := schema.AllResources()
names := make([]string, len(resourceInfos))
i := 0
Expand Down Expand Up @@ -290,7 +290,7 @@ func addFieldSuggestions(fields map[string]llx.Documentation, fieldName string,
// return typ
// }

func blockCallType(typ types.Type, schema llx.Schema) types.Type {
func blockCallType(typ types.Type, schema resources.ResourcesSchema) types.Type {
if typ.IsArray() {
return types.Array(types.Block)
}
Expand Down Expand Up @@ -2171,7 +2171,7 @@ func (c *compiler) CompileParsed(ast *parser.AST) error {
return nil
}

func getMinMondooVersion(schema llx.Schema, current string, resource string, field string) string {
func getMinMondooVersion(schema resources.ResourcesSchema, current string, resource string, field string) string {
info := schema.Lookup(resource)
if info == nil {
return current
Expand Down Expand Up @@ -2242,7 +2242,6 @@ func CompileAST(ast *parser.AST, props map[string]*llx.Primitive, conf CompilerC

// Compile a code piece against a schema into chunky code
func compile(input string, props map[string]*llx.Primitive, compilerConf CompilerConfig) (*llx.CodeBundle, error) {

// remove leading whitespace; we are re-using this later on
input = Dedent(input)

Expand Down
Loading

0 comments on commit 7d1f8a5

Please sign in to comment.