diff --git a/mk2rbc/config_variables.go b/mk2rbc/config_variables.go new file mode 100644 index 000000000..dac509c93 --- /dev/null +++ b/mk2rbc/config_variables.go @@ -0,0 +1,67 @@ +// Copyright 2021 Google LLC +// +// 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 mk2rbc + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "strings" + + mkparser "android/soong/androidmk/parser" +) + +// Extracts the list of product config variables from a file, calling +// given registrar for each variable. +func FindConfigVariables(mkFile string, vr variableRegistrar) error { + mkContents, err := ioutil.ReadFile(mkFile) + if err != nil { + return err + } + parser := mkparser.NewParser(mkFile, bytes.NewBuffer(mkContents)) + nodes, errs := parser.Parse() + if len(errs) > 0 { + for _, e := range errs { + fmt.Fprintln(os.Stderr, "ERROR:", e) + } + return fmt.Errorf("cannot parse %s", mkFile) + } + for _, node := range nodes { + asgn, ok := node.(*mkparser.Assignment) + if !ok { + continue + } + // We are looking for a variable called '_product_list_vars' + // or '_product_single_value_vars'. + if !asgn.Name.Const() { + continue + } + varName := asgn.Name.Strings[0] + var starType starlarkType + if varName == "_product_list_vars" { + starType = starlarkTypeList + } else if varName == "_product_single_value_vars" { + starType = starlarkTypeUnknown + } else { + continue + } + for _, name := range strings.Fields(asgn.Value.Dump()) { + vr.NewVariable(name, VarClassConfig, starType) + } + + } + return nil +} diff --git a/mk2rbc/config_variables_test.go b/mk2rbc/config_variables_test.go new file mode 100644 index 000000000..f5a518049 --- /dev/null +++ b/mk2rbc/config_variables_test.go @@ -0,0 +1,60 @@ +// Copyright 2021 Google LLC +// +// 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 mk2rbc + +import ( + "path/filepath" + "reflect" + "runtime" + "testing" +) + +type testVar struct { + name string + cl varClass + ty starlarkType +} + +type testVariables struct { + v []testVar +} + +func (v *testVariables) NewVariable(name string, varClass varClass, valueType starlarkType) { + v.v = append(v.v, testVar{name, varClass, valueType}) +} + +// getTestDirectory returns the test directory, which should be the test/ subdirectory +func getTestDirectory() string { + _, myFile, _, _ := runtime.Caller(1) + return filepath.Join(filepath.Dir(myFile), "test") +} + +func TestConfigVariables(t *testing.T) { + testFile := filepath.Join(getTestDirectory(), "config_variables.mk.test") + var actual testVariables + if err := FindConfigVariables(testFile, &actual); err != nil { + t.Fatal(err) + } + expected := testVariables{[]testVar{ + {"PRODUCT_NAME", VarClassConfig, starlarkTypeUnknown}, + {"PRODUCT_MODEL", VarClassConfig, starlarkTypeUnknown}, + {"PRODUCT_LOCALES", VarClassConfig, starlarkTypeList}, + {"PRODUCT_AAPT_CONFIG", VarClassConfig, starlarkTypeList}, + {"PRODUCT_AAPT_PREF_CONFIG", VarClassConfig, starlarkTypeUnknown}, + }} + if !reflect.DeepEqual(expected, actual) { + t.Errorf("\nExpected: %v\n Actual: %v", expected, actual) + } +} diff --git a/mk2rbc/test/config_variables.mk.test b/mk2rbc/test/config_variables.mk.test new file mode 100644 index 000000000..e5cd0e928 --- /dev/null +++ b/mk2rbc/test/config_variables.mk.test @@ -0,0 +1,12 @@ +_product_single_value_vars := + +# Variables that are lists of values. +_product_list_vars := + +_product_single_value_vars += PRODUCT_NAME +_product_single_value_vars += PRODUCT_MODEL + +# The resoure configuration options to use for this product. +_product_list_vars += PRODUCT_LOCALES +_product_list_vars += PRODUCT_AAPT_CONFIG +_product_single_value_vars += PRODUCT_AAPT_PREF_CONFIG diff --git a/mk2rbc/types.go b/mk2rbc/types.go new file mode 100644 index 000000000..22c8b58f7 --- /dev/null +++ b/mk2rbc/types.go @@ -0,0 +1,55 @@ +// Copyright 2021 Google LLC +// +// 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 mk2rbc + +// Starlark expression types we use +type starlarkType int + +const ( + starlarkTypeUnknown starlarkType = iota + starlarkTypeList starlarkType = iota + starlarkTypeString starlarkType = iota + starlarkTypeInt starlarkType = iota + starlarkTypeBool starlarkType = iota + starlarkTypeVoid starlarkType = iota +) + +type varClass int + +const ( + VarClassConfig varClass = iota + VarClassSoong varClass = iota + VarClassLocal varClass = iota +) + +type variableRegistrar interface { + NewVariable(name string, varClass varClass, valueType starlarkType) +} + +// ScopeBase is a dummy implementation of the mkparser.Scope. +// All our scopes are read-only and resolve only simple variables. +type ScopeBase struct{} + +func (s ScopeBase) Set(_, _ string) { + panic("implement me") +} + +func (s ScopeBase) Call(_ string, _ []string) []string { + panic("implement me") +} + +func (s ScopeBase) SetFunc(_ string, _ func([]string) []string) { + panic("implement me") +}