Use handcrafted build targets in bp2build

If both bp2build_available and label are specified, label will be
preferred.

Initially, we copy the entire BUILD.bazel file. Eventually we may move
this to use bazel query for a more accurate result.

Test: go test *
Test: build/bazel/scripts/milestone-2/demo.sh full
Test: GENERATE_BAZEL_FILES=true m nothing
      edit bionic/libc/tools/BUILD.bazel
      GENERATE_BAZEL_FILES=true m nothing and verify changes picked up
Bug: 180516554
Change-Id: I43025583300e6b10d2c18032cd4a76237b578d59
diff --git a/android/bazel.go b/android/bazel.go
index 9939bd5..09a2c3a 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -14,19 +14,46 @@
 
 package android
 
-import "android/soong/bazel"
+import (
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+type bazelModuleProperties struct {
+	// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
+	// will import the handcrafted build target into the autogenerated file. Note: this may result in
+	// a conflict due to duplicate targets if bp2build_available is also set.
+	Label *string
+
+	// If true, bp2build will generate the converted Bazel target for this module. Note: this may
+	// cause a conflict due to the duplicate targets if label is also set.
+	Bp2build_available bool
+}
+
+// Properties contains common module properties for Bazel migration purposes.
+type properties struct {
+	// In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
+	// this Soong module.
+	Bazel_module bazelModuleProperties
+}
 
 // BazelModuleBase contains the property structs with metadata for modules which can be converted to
 // Bazel.
 type BazelModuleBase struct {
-	bazelProperties bazel.Properties
+	bazelProperties properties
 }
 
 // Bazelable is specifies the interface for modules that can be converted to Bazel.
 type Bazelable interface {
-	bazelProps() *bazel.Properties
+	bazelProps() *properties
+	HasHandcraftedLabel() bool
 	GetBazelLabel() string
 	ConvertWithBp2build() bool
+	GetBazelBuildFileContents(c Config, path, name string) (string, error)
 }
 
 // BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@@ -42,16 +69,48 @@
 }
 
 // bazelProps returns the Bazel properties for the given BazelModuleBase.
-func (b *BazelModuleBase) bazelProps() *bazel.Properties {
+func (b *BazelModuleBase) bazelProps() *properties {
 	return &b.bazelProperties
 }
 
+// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
+func (b *BazelModuleBase) HasHandcraftedLabel() bool {
+	return b.bazelProperties.Bazel_module.Label != nil
+}
+
+// HandcraftedLabel returns the handcrafted label for this module, or empty string if there is none
+func (b *BazelModuleBase) HandcraftedLabel() string {
+	return proptools.String(b.bazelProperties.Bazel_module.Label)
+}
+
 // GetBazelLabel returns the Bazel label for the given BazelModuleBase.
 func (b *BazelModuleBase) GetBazelLabel() string {
-	return b.bazelProperties.Bazel_module.Label
+	return proptools.String(b.bazelProperties.Bazel_module.Label)
 }
 
 // ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
 func (b *BazelModuleBase) ConvertWithBp2build() bool {
 	return b.bazelProperties.Bazel_module.Bp2build_available
 }
+
+// GetBazelBuildFileContents returns the file contents of a hand-crafted BUILD file if available or
+// an error if there are errors reading the file.
+// TODO(b/181575318): currently we append the whole BUILD file, let's change that to do
+// something more targeted based on the rule type and target.
+func (b *BazelModuleBase) GetBazelBuildFileContents(c Config, path, name string) (string, error) {
+	if !strings.Contains(b.GetBazelLabel(), path) {
+		return "", fmt.Errorf("%q not found in bazel_module.label %q", path, b.GetBazelLabel())
+	}
+	name = filepath.Join(path, name)
+	f, err := c.fs.Open(name)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		return "", err
+	}
+	return string(data[:]), nil
+}