| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package fxicfg |
| |
| import ( |
| "context" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| |
| "fuchsia.googlesource.com/infra/infra/fxicfg/builtins" |
| "fuchsia.googlesource.com/infra/infra/fxicfg/loaders" |
| "fuchsia.googlesource.com/infra/infra/fxicfg/state" |
| "go.chromium.org/luci/starlark/starlarkproto" |
| |
| luci "go.chromium.org/luci/starlark/interpreter" |
| "go.starlark.net/starlark" |
| ) |
| |
| const ( |
| // The default output directory, if one is not supplied. |
| defaultOutputDir = "generated" |
| ) |
| |
| // Generate executes LUCI's starlark interpreter with Fuchsia packages and globals. |
| // |
| // `loader` is the root luci.Loader that knows how to load all client starlark |
| // files. `main` is the file to execute first. |
| // |
| // The interpreter maintains a state.State object that client code modifies. The resulting |
| // state is returned iff execution completed without error. Otherwise, an empty State is |
| // returned. |
| func Generate(loader luci.Loader, main string) (state.State, starlark.StringDict, error) { |
| // load("@stdlib//..."): loads packages compiled into this go binary from starlark |
| // sources in fxicfg/starlark/stdlib/... |
| pkgs := loaders.EmbeddedLoader() |
| |
| // load("@proto//..."): loads fuchsia-specific protobuf modules. |
| pkgs["proto"] = loaders.ProtoLoader() |
| |
| // load("//..."): loads client starlark modules. |
| pkgs[luci.MainPkg] = loader |
| |
| // Proto predeclared provides builtin LUCI textproto functionality. These are included |
| // in the global namespace of all starlark programs. |
| predecl := make(starlark.StringDict) |
| predecl["proto"] = starlarkproto.ProtoLib()["proto"] |
| for k, v := range builtins.All() { |
| predecl[k] = v |
| } |
| |
| tm := state.ThreadModifier(*state.NewState()) |
| interp := luci.Interpreter{ |
| Predeclared: predecl, |
| Packages: pkgs, |
| PreExec: func(th *starlark.Thread, pkg, path string) { |
| tm.WriteTo(th) |
| }, |
| PostExec: func(th *starlark.Thread, pkg, path string) { |
| tm.ReadFrom(th) |
| }, |
| } |
| |
| ctx := context.Background() |
| if err := interp.Init(ctx); err != nil { |
| return state.State{}, nil, err |
| } |
| globals, err := interp.ExecModule(ctx, luci.MainPkg, main) |
| if err != nil { |
| return state.State{}, nil, err |
| } |
| |
| return tm.State(), globals, nil |
| } |
| |
| func CommitState(s state.State) error { |
| dir := s.OutputDir |
| if dir == "" { |
| dir = defaultOutputDir |
| } |
| if err := os.MkdirAll(dir, 0755); err != nil { |
| return err |
| } |
| for k, v := range s.OutputFiles { |
| path := filepath.Join(dir, k) |
| if err := ioutil.WriteFile(path, v, 0644); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |