bp2build: automatically convert all genrules.

Results of `cquery //bionic/...`: https://paste.googleplex.com/5608885982330880?raw

Note that this CL does not contain the global module name mapping to
fully qualified label lookup mechanism, so while the BUILD targets are
queryable, they are not buildable (yet).

Test: GENERATE_BAZEL_FILES=true m nothing && ./build/bazel/scripts/bp2build-sync.sh write && bazel cquery //bionic/...

Change-Id: I6f2316222723d8b612d9b041ca82a188cd05bac9
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 8007574..2bbe4b5 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -11,6 +11,7 @@
     deps: [
         "soong-android",
         "soong-bazel",
+        "soong-genrule",
     ],
     testSrcs: [
         "build_conversion_test.go",
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 2df72bd..e4edc3e 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/genrule"
 	"testing"
 )
 
@@ -302,6 +303,54 @@
     ],
 )`,
 		},
+		{
+			moduleTypeUnderTest:        "genrule",
+			moduleTypeUnderTestFactory: genrule.GenRuleFactory,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tool_files: [":foo.tool"],
+    cmd: "$(location :foo.tool) arg $(in) $(out)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(location :foo.tool) arg $(SRCS) $(OUTS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tool",
+    ],
+)`,
+		},
+		{
+			moduleTypeUnderTest:        "genrule",
+			moduleTypeUnderTestFactory: genrule.GenRuleFactory,
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tools: [":foo.tool"],
+    cmd: "$(location :foo.tool) --out-dir=$(genDir) $(in)",
+}`,
+			expectedBazelTarget: `genrule(
+    name = "foo",
+    cmd = "$(location :foo.tool) --out-dir=$(GENDIR) $(SRCS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        ":foo.tool",
+    ],
+)`,
+		},
 	}
 
 	dir := "."
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8df32f2..1f47dec 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -46,6 +46,8 @@
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
 	})
+
+	android.RegisterBp2BuildMutator("genrule", bp2buildMutator)
 }
 
 var (
@@ -772,6 +774,70 @@
 	Out []string `android:"arch_variant"`
 }
 
+type bazelGenruleAttributes struct {
+	Name  *string
+	Srcs  []string
+	Outs  []string
+	Tools []string
+	Cmd   string
+}
+
+type bazelGenrule struct {
+	android.BazelTargetModuleBase
+	bazelGenruleAttributes
+}
+
+func BazelGenruleFactory() android.Module {
+	module := &bazelGenrule{}
+	module.AddProperties(&module.bazelGenruleAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+func bp2buildMutator(ctx android.TopDownMutatorContext) {
+	if m, ok := ctx.Module().(*Module); ok {
+		name := "__bp2build__" + m.Name()
+		// Replace in and out variables with $< and $@
+		var cmd string
+		if m.properties.Cmd != nil {
+			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+			cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1)
+		}
+
+		// The Out prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outs []string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genRuleProperties); ok {
+				outs = props.Out
+				break
+			}
+		}
+
+		// Bazel only has the "tools" attribute.
+		tools := append(m.properties.Tools, m.properties.Tool_files...)
+
+		// Create the BazelTargetModule.
+		ctx.CreateModule(BazelGenruleFactory, &bazelGenruleAttributes{
+			Name:  proptools.StringPtr(name),
+			Srcs:  m.properties.Srcs,
+			Outs:  outs,
+			Cmd:   cmd,
+			Tools: tools,
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class: "genrule",
+		})
+	}
+}
+
+func (m *bazelGenrule) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelGenrule) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
 var Bool = proptools.Bool
 var String = proptools.String