Simplify Env API: Compute/Components instead of Compute/Walk

Signed-off-by: Solomon Hykes <sh.github.6811@hykes.org>
This commit is contained in:
Solomon Hykes 2021-02-04 20:56:32 +00:00
parent 5b7bc78cf1
commit 0fe2ef4fe4
2 changed files with 57 additions and 41 deletions

View File

@ -165,22 +165,18 @@ func (env *Env) LocalDirs(ctx context.Context) (map[string]string, error) {
lg.Debug().Str("func", "Env.LocalDirs").Interface("result", dirs).Msg("done") lg.Debug().Str("func", "Env.LocalDirs").Interface("result", dirs).Msg("done")
}() }()
// 1. Walk env state, scan compute script for each component. // 1. Walk env state, scan compute script for each component.
_, err := env.Walk(ctx, func(ctx context.Context, c *Component, out *Fillable) error { for _, c := range env.Components() {
lg.Debug(). lg.Debug().
Str("func", "Env.LocalDirs"). Str("func", "Env.LocalDirs").
Str("component", c.Value().Path().String()). Str("component", c.Value().Path().String()).
Msg("scanning next component for local dirs") Msg("scanning next component for local dirs")
cdirs, err := c.LocalDirs(ctx) cdirs, err := c.LocalDirs(ctx)
if err != nil { if err != nil {
return err return dirs, err
} }
for k, v := range cdirs { for k, v := range cdirs {
dirs[k] = v dirs[k] = v
} }
return nil
})
if err != nil {
return dirs, err
} }
// 2. Scan updater script // 2. Scan updater script
updirs, err := env.updater.LocalDirs(ctx) updirs, err := env.updater.LocalDirs(ctx)
@ -193,31 +189,24 @@ func (env *Env) LocalDirs(ctx context.Context) (map[string]string, error) {
return dirs, nil return dirs, nil
} }
// Compute missing values in env configuration, and write them to state. // Return a list of components in the env config.
func (env *Env) Compute(ctx context.Context, s Solver) error { func (env *Env) Components() []*Component {
output, err := env.Walk(ctx, func(ctx context.Context, c *Component, out *Fillable) error { components := []*Component{}
lg := log.Ctx(ctx) env.State().Walk(
func(v *Value) bool {
lg. c, err := NewComponent(v)
Debug(). if os.IsNotExist(err) {
Msg("[Env.Compute] processing") return true
if _, err := c.Compute(ctx, s, out); err != nil { }
lg. if err != nil {
Error(). return false
Err(err). }
Msg("component failed") components = append(components, c)
return err return false // skip nested components, as cueflow does not allow them
} },
return nil nil,
})
if err != nil {
return err
}
return env.set(
env.base,
env.input,
output,
) )
return components
} }
// FIXME: this is just a 3-way merge. Add var args to Value.Merge. // FIXME: this is just a 3-way merge. Add var args to Value.Merge.
@ -285,11 +274,8 @@ func (env *Env) Export(fs FS) (FS, error) {
return fs, nil return fs, nil
} }
// FIXME: don't need ctx here // Compute missing values in env configuration, and write them to state.
type EnvWalkFunc func(context.Context, *Component, *Fillable) error func (env *Env) Compute(ctx context.Context, s Solver) error {
// Walk components and return any computed values
func (env *Env) Walk(ctx context.Context, fn EnvWalkFunc) (*Value, error) {
lg := log.Ctx(ctx) lg := log.Ctx(ctx)
// Cueflow cue instance // Cueflow cue instance
@ -300,9 +286,9 @@ func (env *Env) Walk(ctx context.Context, fn EnvWalkFunc) (*Value, error) {
Msg("walking") Msg("walking")
// Initialize empty output // Initialize empty output
out, err := env.cc.EmptyStruct() output, err := env.cc.EmptyStruct()
if err != nil { if err != nil {
return nil, err return err
} }
// Cueflow config // Cueflow config
@ -325,7 +311,7 @@ func (env *Env) Walk(ctx context.Context, fn EnvWalkFunc) (*Value, error) {
lg.Debug().Msg("cueflow task: filling result") lg.Debug().Msg("cueflow task: filling result")
// Merge task value into output // Merge task value into output
var err error var err error
out, err = out.MergePath(t.Value(), t.Path()) output, err = output.MergePath(t.Value(), t.Path())
if err != nil { if err != nil {
lg. lg.
Error(). Error().
@ -362,15 +348,26 @@ func (env *Env) Walk(ctx context.Context, fn EnvWalkFunc) (*Value, error) {
Str("dependency", dep.Path().String()). Str("dependency", dep.Path().String()).
Msg("dependency detected") Msg("dependency detected")
} }
return fn(ctx, c, NewFillable(t)) if _, err := c.Compute(ctx, s, NewFillable(t)); err != nil {
lg.
Error().
Err(err).
Msg("component failed")
return err
}
return nil
}), nil }), nil
} }
// Orchestrate execution with cueflow // Orchestrate execution with cueflow
flow := cueflow.New(flowCfg, flowInst, flowMatchFn) flow := cueflow.New(flowCfg, flowInst, flowMatchFn)
if err := flow.Run(ctx); err != nil { if err := flow.Run(ctx); err != nil {
return out, err return err
} }
return out, nil return env.set(
env.base,
env.input,
output,
)
} }
// Return the component at the specified path in the config, eg. `www` // Return the component at the specified path in the config, eg. `www`

View File

@ -192,6 +192,25 @@ func (v *Value) IsConcreteR() error {
return v.val.Validate(cue.Concrete(true)) return v.val.Validate(cue.Concrete(true))
} }
func (v *Value) Walk(before func(*Value) bool, after func(*Value)) {
// FIXME: lock?
var (
llBefore func(cue.Value) bool
llAfter func(cue.Value)
)
if before != nil {
llBefore = func(child cue.Value) bool {
return before(v.Wrap(child))
}
}
if after != nil {
llAfter = func(child cue.Value) {
after(v.Wrap(child))
}
}
v.val.Walk(llBefore, llAfter)
}
// Export concrete values to JSON. ignoring non-concrete values. // Export concrete values to JSON. ignoring non-concrete values.
// Contrast with cue.Value.MarshalJSON which requires all values // Contrast with cue.Value.MarshalJSON which requires all values
// to be concrete. // to be concrete.