blob: 47d8dd8138b3d970b412042bedb737206b656690 [file]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package buildconfig
import (
"fmt"
"strings"
log "github.com/golang/glog"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
"go.chromium.org/build/siso/execute"
"go.chromium.org/build/siso/path"
)
const (
// cmd args. tuple
cmdFieldArgs = "args"
// cmd envs. dict
cmdFieldEnvs = "envs"
// cmd dir. string
cmdFieldDir = "dir"
// cmd workspace_root. string
cmdFieldWorkspaceRoot = "workspace_root"
// cmd deps. string
cmdFieldDeps = "deps"
// cmd inputs. list
cmdFieldInputs = "inputs"
// cmd tool_inputs. list
cmdFieldToolInputs = "tool_inputs"
// cmd expanded_inputs. func
cmdFieldExpandedInputs = "expanded_inputs"
// cmd rspfile_content. bytes
cmdFieldRSPFileContent = "rspfile_content"
// cmd outputs. list
cmdFieldOutputs = "outputs"
)
// packCmd packs cmd into Starlark struct.
func packCmd(cmd *execute.Cmd, expandedInputs func() []string) (*starlarkstruct.Struct, error) {
envs, err := packEnvmap(cmd.Env)
if err != nil {
return nil, err
}
outputs := path.Strings(cmd.Outputs)
for _, outdir := range cmd.OutputDirs {
outputs = append(outputs, outdir.String()+"/")
}
return starlarkstruct.FromStringDict(starlark.String("cmd"), map[string]starlark.Value{
cmdFieldArgs: packTuple(cmd.Args),
cmdFieldEnvs: envs,
cmdFieldDir: starlark.String(string(cmd.WorkDir)),
cmdFieldWorkspaceRoot: starlark.String(cmd.WorkspaceRoot),
cmdFieldDeps: starlark.String(cmd.Deps),
cmdFieldInputs: packList(path.Strings(cmd.Inputs)),
cmdFieldToolInputs: packList(path.Strings(cmd.ToolInputs)),
cmdFieldExpandedInputs: starlark.NewBuiltin(cmdFieldExpandedInputs, func(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
log.V(1).Infof("cmd.expanded_inputs")
return packList(expandedInputs()), nil
}),
cmdFieldRSPFileContent: starlark.Bytes(cmd.RSPFileContent),
cmdFieldOutputs: packList(outputs),
}), nil
}
func packTuple(list []string) starlark.Value {
values := make([]starlark.Value, 0, len(list))
for _, elem := range list {
values = append(values, starlark.String(elem))
}
return starlark.Tuple(values)
}
func packEnvmap(envs []string) (starlark.Value, error) {
dict := starlark.NewDict(len(envs))
for _, env := range envs {
k, v, ok := strings.Cut(env, "=")
if !ok {
k = env
v = ""
}
err := dict.SetKey(starlark.String(k), starlark.String(v))
if err != nil {
return nil, fmt.Errorf("set %s=%s: %w", k, v, err)
}
}
return dict, nil
}
func packList(list []string) starlark.Value {
values := make([]starlark.Value, 0, len(list))
for _, elem := range list {
values = append(values, starlark.String(elem))
}
return starlark.NewList(values)
}
func unpackList(v starlark.Value) ([]string, error) {
iterator := starlark.Iterate(v)
if iterator == nil {
return nil, fmt.Errorf("got %v; want iterator", v.Type())
}
defer iterator.Done()
var elem starlark.Value
var list []string
for iterator.Next(&elem) {
s, ok := starlark.AsString(elem)
if !ok {
return nil, fmt.Errorf("got %v in %v; want string", elem.Type(), v.Type())
}
list = append(list, s)
}
return list, nil
}
// uniqueList returns a list that doesn't contain duplicate items.
func uniqueList(inputsList ...[]string) []string {
seen := make(map[string]bool)
var inputs []string
for _, ins := range inputsList {
for _, in := range ins {
if in == "" {
continue
}
if seen[in] {
continue
}
seen[in] = true
inputs = append(inputs, in)
}
}
// make a backing array of slice small enough.
r := make([]string, len(inputs))
copy(r, inputs)
return r
}