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