| // 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 |
| } |