Skip to content

Commit

Permalink
refactor(conductor): use conductor instead of context Values
Browse files Browse the repository at this point in the history
  • Loading branch information
srevinsaju committed Sep 21, 2023
1 parent 3bd7955 commit 33d78c4
Show file tree
Hide file tree
Showing 22 changed files with 370 additions and 466 deletions.
4 changes: 2 additions & 2 deletions cmd/togomak/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func newConfigFromCliContext(ctx *cli.Context) conductor.Config {
}
cfg := conductor.Config{

Behavior: behavior.Behavior{
Behavior: &behavior.Behavior{
Unattended: ctx.Bool("unattended") || ctx.Bool("ci"),
Ci: ctx.Bool("ci"),
DryRun: ctx.Bool("dry-run"),
Expand All @@ -200,7 +200,7 @@ func newConfigFromCliContext(ctx *cli.Context) conductor.Config {
},
},

Paths: path.Path{
Paths: &path.Path{
Pipeline: pipelineFilePath,
Cwd: dir,
Owd: owd,
Expand Down
2 changes: 2 additions & 0 deletions pkg/behavior/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type Child struct {
}

type Behavior struct {
initialized bool

// Unattended is the flag to indicate whether the program is running in unattended mode
Unattended bool

Expand Down
10 changes: 5 additions & 5 deletions pkg/blocks/data/provider_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ import (
)

type ProviderConfig struct {
Paths path.Path
Paths *path.Path

Behavior behavior.Behavior
Behavior *behavior.Behavior
}

func NewDefaultProviderConfig() *ProviderConfig {
return &ProviderConfig{
Paths: path.NewDefaultPath(),
Paths: nil,
}
}

type ProviderOption func(*ProviderConfig)

func WithPaths(paths path.Path) ProviderOption {
func WithPaths(paths *path.Path) ProviderOption {
return func(c *ProviderConfig) {
c.Paths = paths
}
}

func WithBehavior(behavior behavior.Behavior) ProviderOption {
func WithBehavior(behavior *behavior.Behavior) ProviderOption {
return func(c *ProviderConfig) {
c.Behavior = behavior
}
Expand Down
1 change: 1 addition & 0 deletions pkg/ci/data_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func (s *Data) Run(ctx context.Context, options ...runnable.Option) (diags hcl.D
cfg := runnable.NewConfig(options...)
opts := []dataBlock.ProviderOption{
dataBlock.WithPaths(cfg.Paths),
dataBlock.WithBehavior(cfg.Behavior),
}

// region: mutating the data map
Expand Down
4 changes: 2 additions & 2 deletions pkg/ci/pipeline_read.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// Read reads togomak.hcl from the configuration file directory. A configuration file directory is the one that
// contains togomak.hcl, it searches recursively outwards.
// DEPRECATED: use ReadDir instead
func Read(paths path.Path, parser *hclparse.Parser) (*Pipeline, hcl.Diagnostics) {
func Read(paths *path.Path, parser *hclparse.Parser) (*Pipeline, hcl.Diagnostics) {
ciFile := parse.ConfigFilePath(paths)

f, diags := parser.ParseHCLFile(ciFile)
Expand All @@ -39,7 +39,7 @@ func Read(paths path.Path, parser *hclparse.Parser) (*Pipeline, hcl.Diagnostics)

// ReadDir parses an entire directory of *.hcl files and merges them together. This is useful when you want to
// split your pipeline into multiple files, without having to import them individually
func ReadDir(paths path.Path, parser *hclparse.Parser) (*Pipeline, hcl.Diagnostics) {
func ReadDir(paths *path.Path, parser *hclparse.Parser) (*Pipeline, hcl.Diagnostics) {
dir := parse.ConfigFileDir(paths)
return ReadDirFromPath(dir, parser)

Expand Down
4 changes: 2 additions & 2 deletions pkg/ci/runnable.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (r Blocks) Variables() []hcl.Traversal {
return traversal
}

func (r Blocks) Run(ctx context.Context) hcl.Diagnostics {
func (r Blocks) Run(ctx context.Context, opts ...runnable.Option) hcl.Diagnostics {

Check warning on line 91 in pkg/ci/runnable.go

View check run for this annotation

Codecov / codecov/patch

pkg/ci/runnable.go#L91

Added line #L91 was not covered by tests
// run all runnables in parallel, collect errors and return
// create a channel to receive errors
var wg sync.WaitGroup
Expand All @@ -97,7 +97,7 @@ func (r Blocks) Run(ctx context.Context) hcl.Diagnostics {
wg.Add(1)
go func(runnable Block) {
defer wg.Done()
errChan <- runnable.Run(ctx)
errChan <- runnable.Run(ctx, opts...)

Check warning on line 100 in pkg/ci/runnable.go

View check run for this annotation

Codecov / codecov/patch

pkg/ci/runnable.go#L100

Added line #L100 was not covered by tests
}(runnable)
}
wg.Wait()
Expand Down
4 changes: 2 additions & 2 deletions pkg/ci/stage_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (s *Stage) expandMacros(ctx context.Context, opts ...runnable.Option) (*Sta
if !f.IsNull() {
files := f.AsValueMap()
logger.Debugf("using %d files from %s", len(files), macro.Identifier())
err = os.MkdirAll(filepath.Join(cfg.Paths.Cwd, tmpDir, s.Id), 0755)
err = os.MkdirAll(filepath.Join(tmpDir, s.Id), 0755)
if err != nil {
return s, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Expand Down Expand Up @@ -497,7 +497,7 @@ func (s *Stage) Run(ctx context.Context, options ...runnable.Option) (diags hcl.

envStrings = append(envStrings, envParsed)
}
togomakEnvExport := fmt.Sprintf("%s=%s", meta.OutputEnvVar, filepath.Join(cfg.Paths.Cwd, tmpDir, meta.OutputEnvFile))
togomakEnvExport := fmt.Sprintf("%s=%s", meta.OutputEnvVar, filepath.Join(tmpDir, meta.OutputEnvFile))
logger.Tracef("exporting %s", togomakEnvExport)
envStrings = append(envStrings, togomakEnvExport)

Expand Down
4 changes: 2 additions & 2 deletions pkg/conductor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ type Config struct {
User string
Hostname string

Paths path.Path
Paths *path.Path

Interface Interface

// Pipeline is the pipeline configuration
Pipeline ConfigPipeline

// Behavior is the behavior of the program
Behavior behavior.Behavior
Behavior *behavior.Behavior
}
240 changes: 240 additions & 0 deletions pkg/conductor/hcl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package conductor

import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/ext/tryfunc"
yaml "github.com/zclconf/go-cty-yaml"

"github.com/srevinsaju/togomak/v1/pkg/global"
"github.com/srevinsaju/togomak/v1/pkg/meta"
"github.com/srevinsaju/togomak/v1/pkg/third-party/hashicorp/terraform/lang/funcs"
"github.com/srevinsaju/togomak/v1/pkg/ui"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
"github.com/zclconf/go-cty/cty/function/stdlib"
"os"
"os/exec"
"time"
)

func CreateEvalContext(cfg Config, process Process) *hcl.EvalContext {
// --> set up HCL context
paths := cfg.Paths
behavior := cfg.Behavior
hclContext := &hcl.EvalContext{
Functions: map[string]function.Function{
"abs": stdlib.AbsoluteFunc,
"abspath": funcs.AbsPathFunc,
"alltrue": funcs.AllTrueFunc,
"anytrue": funcs.AnyTrueFunc,
"basename": funcs.BasenameFunc,
"base64decode": funcs.Base64DecodeFunc,
"base64encode": funcs.Base64EncodeFunc,
"base64gzip": funcs.Base64GzipFunc,
"base64sha256": funcs.Base64Sha256Func,
"base64sha512": funcs.Base64Sha512Func,
"bcrypt": funcs.BcryptFunc,
"can": tryfunc.CanFunc,
"ceil": stdlib.CeilFunc,
"chomp": stdlib.ChompFunc,
"coalesce": funcs.CoalesceFunc,
"coalescelist": stdlib.CoalesceListFunc,
"compact": stdlib.CompactFunc,
"concat": stdlib.ConcatFunc,
"contains": stdlib.ContainsFunc,
"csvdecode": stdlib.CSVDecodeFunc,
"dirname": funcs.DirnameFunc,
"distinct": stdlib.DistinctFunc,
"element": stdlib.ElementFunc,
"endswith": funcs.EndsWithFunc,
"chunklist": stdlib.ChunklistFunc,
"file": funcs.MakeFileFunc(paths.Cwd, false),
"fileexists": funcs.MakeFileExistsFunc(paths.Cwd),
"fileset": funcs.MakeFileSetFunc(paths.Cwd),
"filebase64": funcs.MakeFileFunc(paths.Cwd, true),
"filebase64sha256": funcs.MakeFileBase64Sha256Func(paths.Cwd),
"filebase64sha512": funcs.MakeFileBase64Sha512Func(paths.Cwd),
"filemd5": funcs.MakeFileMd5Func(paths.Cwd),
"filesha1": funcs.MakeFileSha1Func(paths.Cwd),
"filesha256": funcs.MakeFileSha256Func(paths.Cwd),
"filesha512": funcs.MakeFileSha512Func(paths.Cwd),
"flatten": stdlib.FlattenFunc,
"floor": stdlib.FloorFunc,
"format": stdlib.FormatFunc,
"formatdate": stdlib.FormatDateFunc,
"formatlist": stdlib.FormatListFunc,
"indent": stdlib.IndentFunc,
"index": funcs.IndexFunc, // stdlib.IndexFunc is not compatible
"join": stdlib.JoinFunc,
"jsondecode": stdlib.JSONDecodeFunc,
"jsonencode": stdlib.JSONEncodeFunc,
"keys": stdlib.KeysFunc,
"length": funcs.LengthFunc,
"list": funcs.ListFunc,
"log": stdlib.LogFunc,
"lookup": funcs.LookupFunc,
"lower": stdlib.LowerFunc,
"map": funcs.MapFunc,
"matchkeys": funcs.MatchkeysFunc,
"max": stdlib.MaxFunc,
"md5": funcs.Md5Func,
"merge": stdlib.MergeFunc,
"min": stdlib.MinFunc,
"one": funcs.OneFunc,
"parseint": stdlib.ParseIntFunc,
"pathexpand": funcs.PathExpandFunc,
"pow": stdlib.PowFunc,
"range": stdlib.RangeFunc,
"regex": stdlib.RegexFunc,
"regexall": stdlib.RegexAllFunc,
"replace": funcs.ReplaceFunc,
"reverse": stdlib.ReverseListFunc,
"rsadecrypt": funcs.RsaDecryptFunc,
"sensitive": funcs.SensitiveFunc,
"nonsensitive": funcs.NonsensitiveFunc,
"setintersection": stdlib.SetIntersectionFunc,
"setproduct": stdlib.SetProductFunc,
"setsubtract": stdlib.SetSubtractFunc,
"setunion": stdlib.SetUnionFunc,
"sha1": funcs.Sha1Func,
"sha256": funcs.Sha256Func,
"sha512": funcs.Sha512Func,
"signum": stdlib.SignumFunc,
"slice": stdlib.SliceFunc,
"sort": stdlib.SortFunc,
"split": stdlib.SplitFunc,
"startswith": funcs.StartsWithFunc,
"strcontains": funcs.StrContainsFunc,
"strrev": stdlib.ReverseFunc,
"substr": stdlib.SubstrFunc,
"sum": funcs.SumFunc,
"textdecodebase64": funcs.TextDecodeBase64Func,
"textencodebase64": funcs.TextEncodeBase64Func,
"timestamp": funcs.TimestampFunc,
"timeadd": stdlib.TimeAddFunc,
"timecmp": funcs.TimeCmpFunc,
"title": stdlib.TitleFunc,
"tostring": funcs.MakeToFunc(cty.String),
"tonumber": funcs.MakeToFunc(cty.Number),
"tobool": funcs.MakeToFunc(cty.Bool),
"toset": funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
"tolist": funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
"tomap": funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
"transpose": funcs.TransposeFunc,
"trim": stdlib.TrimFunc,
"trimprefix": stdlib.TrimPrefixFunc,
"trimspace": stdlib.TrimSpaceFunc,
"trimsuffix": stdlib.TrimSuffixFunc,
"try": tryfunc.TryFunc,
"upper": stdlib.UpperFunc,
"urlencode": funcs.URLEncodeFunc,
"uuid": funcs.UUIDFunc,
"uuidv5": funcs.UUIDV5Func,
"values": stdlib.ValuesFunc,
"which": function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "executable",
AllowDynamicType: true,
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
path, err := exec.LookPath(args[0].AsString())
if err != nil {
return cty.StringVal(""), err
}
return cty.StringVal(path), nil

Check warning on line 148 in pkg/conductor/hcl.go

View check run for this annotation

Codecov / codecov/patch

pkg/conductor/hcl.go#L144-L148

Added lines #L144 - L148 were not covered by tests
},
Description: "Returns the absolute path to an executable in the current PATH.",
}),
"yamldecode": yaml.YAMLDecodeFunc,
"yamlencode": yaml.YAMLEncodeFunc,
"zipmap": stdlib.ZipmapFunc,

"ansifmt": ui.AnsiFunc,
"env": function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "Key of the environment variable",
AllowDynamicType: true,
Type: cty.String,
},
},
VarParam: &function.Parameter{
Name: "lists",
Description: "One or more lists of strings to join.",
Type: cty.String,
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
v, ok := os.LookupEnv(args[0].AsString())
if ok {
return cty.StringVal(v), nil
}
def := args[1]
return def, nil
},
Description: "Returns the value of the environment variable, returns the default value if environment variable is empty, else returns empty string.",
}),
},

Variables: map[string]cty.Value{
"true": cty.True,
"false": cty.False,
"null": cty.NullVal(cty.DynamicPseudoType),

"owd": cty.StringVal(paths.Owd),
"cwd": cty.StringVal(paths.Cwd),
"hostname": cty.StringVal(cfg.Hostname),
"hostuser": cty.StringVal(cfg.User),

"pipeline": cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal(process.Id.String()),
"path": cty.StringVal(paths.Pipeline),
"tempDir": cty.StringVal(process.TempDir),
}),

"togomak": cty.ObjectVal(map[string]cty.Value{
"version": cty.StringVal(meta.AppVersion),
"boot_time": cty.StringVal(time.Now().Format(time.RFC3339)),
"boot_time_unix": cty.NumberIntVal(time.Now().Unix()),
"pipeline_id": cty.StringVal(process.Id.String()),
"ci": cty.BoolVal(behavior.Ci),
"unattended": cty.BoolVal(behavior.Unattended),
}),

// introduced in v1.5.0
"ansi": cty.ObjectVal(map[string]cty.Value{
"bg": cty.ObjectVal(map[string]cty.Value{
"red": cty.StringVal("\033[41m"),
"green": cty.StringVal("\033[42m"),
"yellow": cty.StringVal("\033[43m"),
"blue": cty.StringVal("\033[44m"),
"purple": cty.StringVal("\033[45m"),
"cyan": cty.StringVal("\033[46m"),
"white": cty.StringVal("\033[47m"),
"grey": cty.StringVal("\033[100m"),
}),
"fg": cty.ObjectVal(map[string]cty.Value{
"red": cty.StringVal("\033[31m"),
"green": cty.StringVal("\033[32m"),
"yellow": cty.StringVal("\033[33m"),
"blue": cty.StringVal("\033[34m"),
"purple": cty.StringVal("\033[35m"),
"cyan": cty.StringVal("\033[36m"),
"white": cty.StringVal("\033[37m"),
"grey": cty.StringVal("\033[90m"),
"bold": cty.StringVal("\033[1m"),
"italic": cty.StringVal("\033[3m"),
"underline": cty.StringVal("\033[4m"),
}),

"reset": cty.StringVal("\033[0m"),
}),
},
}
global.SetHclEvalContext(hclContext)
return hclContext
}
Loading

0 comments on commit 33d78c4

Please sign in to comment.