blob: 3696127377e902100161cba0bd34737c767dab37 [file] [log] [blame]
// Copyright 2018 The LUCI Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package lucicfg
import (
// genCtx is a starlark struct that represents the state passed to generator
// callbacks (as first and only argument).
type genCtx struct {
output *outputBuilder
roots map[string]string // name of the set => its root directory
func newGenCtx() *genCtx {
ctx := &genCtx{
output: newOutputBuilder(),
roots: map[string]string{},
ctx.Struct = *starlarkstruct.FromStringDict(starlark.String("gen_ctx"), starlark.StringDict{
"output": ctx.output,
"declare_config_set": starlark.NewBuiltin("declare_config_set", ctx.declareConfigSetImpl),
return ctx
func (c *genCtx) declareConfigSetImpl(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var name starlark.String
var root starlark.String
err := starlark.UnpackArgs("declare_config_set", args, kwargs,
"name", &name,
"root", &root)
if err != nil {
return nil, err
nameS := name.GoString()
// Paths must be within the config output directory, "../" is not allowed.
rootS, err := cleanRelativePath("", root.GoString(), false)
if err != nil {
return nil, fmt.Errorf("declare_config_set: root - %s", err)
// It is OK to redeclare exact same root. It is not OK to change it.
if existing, ok := c.roots[nameS]; ok && existing != rootS {
return nil, fmt.Errorf("declare_config_set: set %q has already been declared", nameS)
c.roots[nameS] = rootS
return starlark.None, nil
func (c *genCtx) assembleOutput(includePBHeader bool) (Output, error) {
files, err := c.output.finalize(includePBHeader)
return Output{
Data: files,
Roots: c.roots,
}, err
func init() {
// new_gen_ctx() makes a new empty generator context object.
declNative("new_gen_ctx", func(call nativeCall) (starlark.Value, error) {
if err := call.unpack(0); err != nil {
return nil, err
return newGenCtx(), nil