blob: 182712a697f1be442944f0b7c0449a52e58cbf3e [file] [log] [blame]
// Copyright 2019 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package base
import (
"context"
"fmt"
"os"
"path/filepath"
"go.chromium.org/luci/common/logging"
"go.chromium.org/luci/starlark/interpreter"
"go.chromium.org/luci/lucicfg"
)
// GenerateConfigs executes the Starlark script and assembles final values for
// meta config.
//
// It is a common part of subcommands that generate configs.
//
// 'meta' is initial Meta config with default parameters, it will be mutated
// in-place to contain the final parameters (based on meta.config(...) calls in
// Starlark and the config populated via CLI flags, passed as 'flags'). 'flags'
// are also mutated in-place to rebase ConfigDir onto cwd.
func GenerateConfigs(ctx context.Context, inputFile string, meta, flags *lucicfg.Meta) (lucicfg.ConfigSet, error) {
abs, err := filepath.Abs(inputFile)
if err != nil {
return nil, err
}
// Make sure the input file exists, to make the error message in this case be
// more humane. lucicfg.Generate will formulate this error as "no such module"
// which looks confusing.
switch _, err := os.Stat(abs); {
case os.IsNotExist(err):
return nil, fmt.Errorf("no such file: %s", inputFile)
case err != nil:
return nil, err
}
// The directory with the input file becomes the root of the main package.
root, main := filepath.Split(abs)
// Generate everything, storing the result in memory.
logging.Infof(ctx, "Generating configs...")
state, err := lucicfg.Generate(ctx, lucicfg.Inputs{
Code: interpreter.FileSystemLoader(root),
Entry: main,
TextPBHeader: "# Auto-generated by lucicfg.\n# Do not modify manually.\n\n",
})
if err != nil {
return nil, err
}
// Config dir in the default meta, and if set from Starlark, is relative to
// the main package root. It is relative to cwd ONLY when explicitly provided
// via -config-dir CLI flag. Note that ".." is allowed.
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
meta.RebaseConfigDir(root)
state.Meta.RebaseConfigDir(root)
flags.RebaseConfigDir(cwd)
// Figure out the final meta config: values set via starlark override
// defaults, and values passed explicitly via CLI flags override what is
// in starlark.
meta.PopulateFromTouchedIn(&state.Meta)
meta.PopulateFromTouchedIn(flags)
meta.Log(ctx)
return state.Configs, nil
}