Bp2Build common properties auto-handling

Introduce `commonAttributes` & `fillCommonBp2BuildModuleAttrs used in
CreateBazelTargetModule

Adapt `bp2BuildInfo` to use `commonAttrs` instead of `Name`.
And thus also all downstream users of `CreateBazelTargetModule`.

As initial user, the Soong `required` property will be
translated to Bazel's `data`.

Bug: 198146582, 196091467
Test: build_converstion_test.go:TestCommonBp2BuildModuleAttrs
Test: go test
Test: mixed_{libc,droid}.sh
Change-Id: Ib500e40f7e2cb48c459f1ebe3188962fc41ec124
This commit is contained in:
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux
2021-08-31 20:30:36 +00:00
parent 9c03ef7790
commit 447f6c99c9
18 changed files with 229 additions and 51 deletions

View File

@@ -72,7 +72,7 @@ func FilegroupBp2Build(ctx TopDownMutatorContext) {
Bzl_load_location: "//build/bazel/rules:filegroup.bzl", Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
} }
ctx.CreateBazelTargetModule(fg.Name(), props, attrs) ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
} }
type fileGroupProperties struct { type fileGroupProperties struct {

View File

@@ -852,6 +852,16 @@ type commonProperties struct {
UnconvertedBp2buildDeps []string `blueprint:"mutated"` UnconvertedBp2buildDeps []string `blueprint:"mutated"`
} }
// CommonAttributes represents the common Bazel attributes from which properties
// in `commonProperties` are translated/mapped; such properties are annotated in
// a list their corresponding attribute. It is embedded within `bp2buildInfo`.
type CommonAttributes struct {
// Soong nameProperties -> Bazel name
Name string
// Data mapped from: Required
Data bazel.LabelListAttribute
}
type distProperties struct { type distProperties struct {
// configuration to distribute output files from this module to the distribution // configuration to distribute output files from this module to the distribution
// directory (default: $OUT/dist, configurable with $DIST_DIR) // directory (default: $OUT/dist, configurable with $DIST_DIR)
@@ -1072,6 +1082,34 @@ func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupport
m.base().commonProperties.CreateCommonOSVariant = true m.base().commonProperties.CreateCommonOSVariant = true
} }
func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext) {
// Assert passed-in attributes include Name
name := attrs.Name
if len(name) == 0 {
ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
}
mod := ctx.Module().base()
props := &mod.commonProperties
depsToLabelList := func(deps []string) bazel.LabelListAttribute {
return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps))
}
data := &attrs.Data
required := depsToLabelList(props.Required)
archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
for axis, configToProps := range archVariantProps {
for config, _props := range configToProps {
if archProps, ok := _props.(*commonProperties); ok {
required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
}
}
}
data.Append(required)
}
// A ModuleBase object contains the properties that are common to all Android // A ModuleBase object contains the properties that are common to all Android
// modules. It should be included as an anonymous field in every module // modules. It should be included as an anonymous field in every module
// struct definition. InitAndroidModule should then be called from the module's // struct definition. InitAndroidModule should then be called from the module's
@@ -1183,15 +1221,15 @@ type ModuleBase struct {
// A struct containing all relevant information about a Bazel target converted via bp2build. // A struct containing all relevant information about a Bazel target converted via bp2build.
type bp2buildInfo struct { type bp2buildInfo struct {
Name string Dir string
Dir string BazelProps bazel.BazelTargetModuleProperties
BazelProps bazel.BazelTargetModuleProperties CommonAttrs CommonAttributes
Attrs interface{} Attrs interface{}
} }
// TargetName returns the Bazel target name of a bp2build converted target. // TargetName returns the Bazel target name of a bp2build converted target.
func (b bp2buildInfo) TargetName() string { func (b bp2buildInfo) TargetName() string {
return b.Name return b.CommonAttrs.Name
} }
// TargetPackage returns the Bazel package of a bp2build converted target. // TargetPackage returns the Bazel package of a bp2build converted target.
@@ -1211,8 +1249,8 @@ func (b bp2buildInfo) BazelRuleLoadLocation() string {
} }
// BazelAttributes returns the Bazel attributes of a bp2build converted target. // BazelAttributes returns the Bazel attributes of a bp2build converted target.
func (b bp2buildInfo) BazelAttributes() interface{} { func (b bp2buildInfo) BazelAttributes() []interface{} {
return b.Attrs return []interface{}{&b.CommonAttrs, b.Attrs}
} }
func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) { func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {

View File

@@ -15,10 +15,11 @@
package android package android
import ( import (
"android/soong/bazel"
"reflect" "reflect"
"sync" "sync"
"android/soong/bazel"
"github.com/google/blueprint" "github.com/google/blueprint"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
) )
@@ -268,7 +269,7 @@ type TopDownMutatorContext interface {
// factory method, just like in CreateModule, but also requires // factory method, just like in CreateModule, but also requires
// BazelTargetModuleProperties containing additional metadata for the // BazelTargetModuleProperties containing additional metadata for the
// bp2build codegenerator. // bp2build codegenerator.
CreateBazelTargetModule(string, bazel.BazelTargetModuleProperties, interface{}) CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
} }
type topDownMutatorContext struct { type topDownMutatorContext struct {
@@ -514,17 +515,18 @@ func registerDepsMutatorBp2Build(ctx RegisterMutatorsContext) {
} }
func (t *topDownMutatorContext) CreateBazelTargetModule( func (t *topDownMutatorContext) CreateBazelTargetModule(
name string,
bazelProps bazel.BazelTargetModuleProperties, bazelProps bazel.BazelTargetModuleProperties,
commonAttrs CommonAttributes,
attrs interface{}) { attrs interface{}) {
commonAttrs.fillCommonBp2BuildModuleAttrs(t)
mod := t.Module()
info := bp2buildInfo{ info := bp2buildInfo{
Name: name, Dir: t.OtherModuleDir(mod),
Dir: t.OtherModuleDir(t.Module()), BazelProps: bazelProps,
BazelProps: bazelProps, CommonAttrs: commonAttrs,
Attrs: attrs, Attrs: attrs,
} }
t.Module().base().addBp2buildInfo(info) mod.base().addBp2buildInfo(info)
} }
func (t *topDownMutatorContext) AppendProperties(props ...interface{}) { func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {

View File

@@ -3325,5 +3325,5 @@ func apexBundleBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexB
Bzl_load_location: "//build/bazel/rules:apex.bzl", Bzl_load_location: "//build/bazel/rules:apex.bzl",
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }

View File

@@ -240,5 +240,5 @@ func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey)
Bzl_load_location: "//build/bazel/rules:apex_key.bzl", Bzl_load_location: "//build/bazel/rules:apex_key.bzl",
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }

View File

@@ -411,7 +411,7 @@ type bp2buildModule interface {
TargetPackage() string TargetPackage() string
BazelRuleClass() string BazelRuleClass() string
BazelRuleLoadLocation() string BazelRuleLoadLocation() string
BazelAttributes() interface{} BazelAttributes() []interface{}
} }
func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget { func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget {
@@ -419,7 +419,8 @@ func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget {
bzlLoadLocation := m.BazelRuleLoadLocation() bzlLoadLocation := m.BazelRuleLoadLocation()
// extract the bazel attributes from the module. // extract the bazel attributes from the module.
props := extractModuleProperties([]interface{}{m.BazelAttributes()}) attrs := m.BazelAttributes()
props := extractModuleProperties(attrs, true)
delete(props.Attrs, "bp2build_available") delete(props.Attrs, "bp2build_available")
@@ -482,14 +483,14 @@ func getBuildProperties(ctx bpToBuildContext, m blueprint.Module) BazelAttribute
// TODO: this omits properties for blueprint modules (blueprint_go_binary, // TODO: this omits properties for blueprint modules (blueprint_go_binary,
// bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately. // bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately.
if aModule, ok := m.(android.Module); ok { if aModule, ok := m.(android.Module); ok {
return extractModuleProperties(aModule.GetProperties()) return extractModuleProperties(aModule.GetProperties(), false)
} }
return BazelAttributes{} return BazelAttributes{}
} }
// Generically extract module properties and types into a map, keyed by the module property name. // Generically extract module properties and types into a map, keyed by the module property name.
func extractModuleProperties(props []interface{}) BazelAttributes { func extractModuleProperties(props []interface{}, checkForDuplicateProperties bool) BazelAttributes {
ret := map[string]string{} ret := map[string]string{}
// Iterate over this android.Module's property structs. // Iterate over this android.Module's property structs.
@@ -503,6 +504,11 @@ func extractModuleProperties(props []interface{}) BazelAttributes {
if isStructPtr(propertiesValue.Type()) { if isStructPtr(propertiesValue.Type()) {
structValue := propertiesValue.Elem() structValue := propertiesValue.Elem()
for k, v := range extractStructProperties(structValue, 0) { for k, v := range extractStructProperties(structValue, 0) {
if existing, exists := ret[k]; checkForDuplicateProperties && exists {
panic(fmt.Errorf(
"%s (%v) is present in properties whereas it should be consolidated into a commonAttributes",
k, existing))
}
ret[k] = v ret[k] = v
} }
} else { } else {

View File

@@ -15,10 +15,12 @@
package bp2build package bp2build
import ( import (
"android/soong/android"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
"android/soong/android"
"android/soong/python"
) )
func TestGenerateSoongModuleTargets(t *testing.T) { func TestGenerateSoongModuleTargets(t *testing.T) {
@@ -1215,3 +1217,133 @@ func TestGlobExcludeSrcs(t *testing.T) {
} }
} }
} }
func TestCommonBp2BuildModuleAttrs(t *testing.T) {
testCases := []bp2buildTestCase{
{
description: "Required into data test",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
blueprint: `filegroup {
name: "reqd",
}
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{`filegroup(
name = "fg_foo",
data = [":reqd"],
)`,
`filegroup(
name = "reqd",
)`,
},
},
{
description: "Required via arch into data test",
moduleTypeUnderTest: "python_library",
moduleTypeUnderTestFactory: python.PythonLibraryFactory,
moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
blueprint: `python_library {
name: "reqdx86",
bazel_module: { bp2build_available: false, },
}
python_library {
name: "reqdarm",
bazel_module: { bp2build_available: false, },
}
python_library {
name: "fg_foo",
arch: {
arm: {
required: ["reqdarm"],
},
x86: {
required: ["reqdx86"],
},
},
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{`py_library(
name = "fg_foo",
data = select({
"//build/bazel/platforms/arch:arm": [":reqdarm"],
"//build/bazel/platforms/arch:x86": [":reqdx86"],
"//conditions:default": [],
}),
srcs_version = "PY3",
)`,
},
},
{
description: "Required appended to data test",
moduleTypeUnderTest: "python_library",
moduleTypeUnderTestFactory: python.PythonLibraryFactory,
moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
blueprint: `python_library {
name: "reqd",
srcs: ["src.py"],
}
python_library {
name: "fg_foo",
data: ["data.bin"],
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
`py_library(
name = "fg_foo",
data = [
"data.bin",
":reqd",
],
srcs_version = "PY3",
)`,
`py_library(
name = "reqd",
srcs = ["src.py"],
srcs_version = "PY3",
)`,
},
filesystem: map[string]string{
"data.bin": "",
"src.py": "",
},
},
{
description: "All props-to-attrs at once together test",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
blueprint: `filegroup {
name: "reqd"
}
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
`filegroup(
name = "fg_foo",
data = [":reqd"],
)`,
`filegroup(
name = "reqd",
)`,
},
filesystem: map[string]string{},
},
}
for _, test := range testCases {
runBp2BuildTestCaseSimple(t, test)
}
}

View File

@@ -1,12 +1,13 @@
package bp2build package bp2build
import ( import (
"android/soong/android"
"android/soong/cc/config"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"android/soong/android"
"android/soong/cc/config"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
) )

View File

@@ -135,17 +135,14 @@ func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi
android.FailIfErrored(t, errs) android.FailIfErrored(t, errs)
} }
if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target, got %d; %v", t.Errorf("%s: Expected %d bazel target, got `%d``",
tc.description, expectedCount, actualCount, bazelTargets) tc.description, expectedCount, actualCount)
} else { } else {
for i, target := range bazelTargets { for i, target := range bazelTargets {
if w, g := tc.expectedBazelTargets[i], target.content; w != g { if w, g := tc.expectedBazelTargets[i], target.content; w != g {
t.Errorf( t.Errorf(
"%s: Expected generated Bazel target to be '%s', got '%s'", "%s: Expected generated Bazel target to be `%s`, got `%s`",
tc.description, tc.description, w, g)
w,
g,
)
} }
} }
} }
@@ -312,7 +309,7 @@ func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
Rule_class: "custom", Rule_class: "custom",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
} }
} }
@@ -331,19 +328,19 @@ func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
Rule_class: "my_library", Rule_class: "my_library",
Bzl_load_location: "//build/bazel/rules:rules.bzl", Bzl_load_location: "//build/bazel/rules:rules.bzl",
} }
ctx.CreateBazelTargetModule(baseName, myLibraryProps, attrs) ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
protoLibraryProps := bazel.BazelTargetModuleProperties{ protoLibraryProps := bazel.BazelTargetModuleProperties{
Rule_class: "proto_library", Rule_class: "proto_library",
Bzl_load_location: "//build/bazel/rules:proto.bzl", Bzl_load_location: "//build/bazel/rules:proto.bzl",
} }
ctx.CreateBazelTargetModule(baseName+"_proto_library_deps", protoLibraryProps, attrs) ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
myProtoLibraryProps := bazel.BazelTargetModuleProperties{ myProtoLibraryProps := bazel.BazelTargetModuleProperties{
Rule_class: "my_proto_library", Rule_class: "my_proto_library",
Bzl_load_location: "//build/bazel/rules:proto.bzl", Bzl_load_location: "//build/bazel/rules:proto.bzl",
} }
ctx.CreateBazelTargetModule(baseName+"_my_proto_library_deps", myProtoLibraryProps, attrs) ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
} }
} }

View File

@@ -345,7 +345,7 @@ func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl", Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
} }
// cc_library creates both static and/or shared libraries for a device and/or // cc_library creates both static and/or shared libraries for a device and/or
@@ -2434,7 +2434,7 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext,
Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType), Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType),
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }
// TODO(b/199902614): Can this be factored to share with the other Attributes? // TODO(b/199902614): Can this be factored to share with the other Attributes?

View File

@@ -147,5 +147,5 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) {
Bzl_load_location: "//build/bazel/rules:cc_library_headers.bzl", Bzl_load_location: "//build/bazel/rules:cc_library_headers.bzl",
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }

View File

@@ -206,7 +206,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) {
Bzl_load_location: "//build/bazel/rules:cc_object.bzl", Bzl_load_location: "//build/bazel/rules:cc_object.bzl",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
} }
func (object *objectLinker) appendLdflags(flags []string) { func (object *objectLinker) appendLdflags(flags []string) {

View File

@@ -704,5 +704,5 @@ func prebuiltEtcBp2BuildInternal(ctx android.TopDownMutatorContext, module *Preb
Bzl_load_location: "//build/bazel/rules:prebuilt_etc.bzl", Bzl_load_location: "//build/bazel/rules:prebuilt_etc.bzl",
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }

View File

@@ -928,7 +928,7 @@ func genruleBp2Build(ctx android.TopDownMutatorContext) {
} }
// Create the BazelTargetModule. // Create the BazelTargetModule.
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
} }
var Bool = proptools.Bool var Bool = proptools.Bool

View File

@@ -1431,5 +1431,5 @@ func androidAppCertificateBp2BuildInternal(ctx android.TopDownMutatorContext, mo
Bzl_load_location: "//build/bazel/rules:android_app_certificate.bzl", Bzl_load_location: "//build/bazel/rules:android_app_certificate.bzl",
} }
ctx.CreateBazelTargetModule(module.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
} }

View File

@@ -37,7 +37,6 @@ func registerPythonBinaryComponents(ctx android.RegistrationContext) {
type bazelPythonBinaryAttributes struct { type bazelPythonBinaryAttributes struct {
Main string Main string
Srcs bazel.LabelListAttribute Srcs bazel.LabelListAttribute
Data bazel.LabelListAttribute
Deps bazel.LabelListAttribute Deps bazel.LabelListAttribute
Python_version string Python_version string
} }
@@ -85,7 +84,6 @@ func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) {
attrs := &bazelPythonBinaryAttributes{ attrs := &bazelPythonBinaryAttributes{
Main: main, Main: main,
Srcs: baseAttrs.Srcs, Srcs: baseAttrs.Srcs,
Data: baseAttrs.Data,
Deps: baseAttrs.Deps, Deps: baseAttrs.Deps,
Python_version: python_version, Python_version: python_version,
} }
@@ -95,7 +93,10 @@ func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) {
Rule_class: "py_binary", Rule_class: "py_binary",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: m.Name(),
Data: baseAttrs.Data,
}, attrs)
} }
type BinaryProperties struct { type BinaryProperties struct {

View File

@@ -45,7 +45,6 @@ func PythonLibraryHostFactory() android.Module {
type bazelPythonLibraryAttributes struct { type bazelPythonLibraryAttributes struct {
Srcs bazel.LabelListAttribute Srcs bazel.LabelListAttribute
Data bazel.LabelListAttribute
Deps bazel.LabelListAttribute Deps bazel.LabelListAttribute
Srcs_version string Srcs_version string
} }
@@ -91,7 +90,6 @@ func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) {
baseAttrs := m.makeArchVariantBaseAttributes(ctx) baseAttrs := m.makeArchVariantBaseAttributes(ctx)
attrs := &bazelPythonLibraryAttributes{ attrs := &bazelPythonLibraryAttributes{
Srcs: baseAttrs.Srcs, Srcs: baseAttrs.Srcs,
Data: baseAttrs.Data,
Deps: baseAttrs.Deps, Deps: baseAttrs.Deps,
Srcs_version: python_version, Srcs_version: python_version,
} }
@@ -101,7 +99,10 @@ func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) {
Rule_class: "py_library", Rule_class: "py_library",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: m.Name(),
Data: baseAttrs.Data,
}, attrs)
} }
func PythonLibraryFactory() android.Module { func PythonLibraryFactory() android.Module {

View File

@@ -548,7 +548,7 @@ func ShBinaryBp2Build(ctx android.TopDownMutatorContext) {
Rule_class: "sh_binary", Rule_class: "sh_binary",
} }
ctx.CreateBazelTargetModule(m.Name(), props, attrs) ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
} }
var Bool = proptools.Bool var Bool = proptools.Bool