Merge "Mark hansson and paulduffin last resort reviewers"
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 672d7f6..a407b5e 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -329,6 +329,7 @@
//system/extras/ext4_utils
"libext4_utils",
+ "mke2fs_conf",
//system/extras/libfec
"libfec",
@@ -359,10 +360,10 @@
"gen-kotlin-build-file.py", // TODO(b/198619163) module has same name as source
"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
"linkerconfig", "mdnsd", // TODO(b/202876379): has arch-variant static_executable
- "linker", // TODO(b/228316882): cc_binary uses link_crt
- "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
- "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
- "apexer", "apexer_test", // Requires aapt2
+ "linker", // TODO(b/228316882): cc_binary uses link_crt
+ "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
+ "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+ "apexer_test", // Requires aapt2
"apexer_test_host_tools",
"host_apex_verifier",
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 8ab003c..8834c11 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -111,7 +111,7 @@
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
- InvokeBazel() error
+ InvokeBazel(config Config) error
// Returns true if bazel is enabled for the given configuration.
BazelEnabled() bool
@@ -191,7 +191,7 @@
return result, nil
}
-func (m MockBazelContext) InvokeBazel() error {
+func (m MockBazelContext) InvokeBazel(config Config) error {
panic("unimplemented")
}
@@ -261,7 +261,7 @@
panic("unimplemented")
}
-func (n noopBazelContext) InvokeBazel() error {
+func (n noopBazelContext) InvokeBazel(config Config) error {
panic("unimplemented")
}
@@ -361,6 +361,7 @@
type mockBazelRunner struct {
bazelCommandResults map[bazelCommand]string
commands []bazelCommand
+ extraFlags []string
}
func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
@@ -368,6 +369,7 @@
command bazelCommand,
extraFlags ...string) (string, string, error) {
r.commands = append(r.commands, command)
+ r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
if ret, ok := r.bazelCommandResults[command]; ok {
return ret, "", nil
}
@@ -676,7 +678,7 @@
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
-func (context *bazelContext) InvokeBazel() error {
+func (context *bazelContext) InvokeBazel(config Config) error {
context.results = make(map[cqueryKey]string)
var cqueryOutput string
@@ -759,15 +761,31 @@
// Issue an aquery command to retrieve action information about the bazel build tree.
//
- // TODO(cparsons): Use --target_pattern_file to avoid command line limits.
var aqueryOutput string
+ var coverageFlags []string
+ if Bool(config.productVariables.ClangCoverage) {
+ coverageFlags = append(coverageFlags, "--collect_code_coverage")
+ if len(config.productVariables.NativeCoveragePaths) > 0 ||
+ len(config.productVariables.NativeCoverageExcludePaths) > 0 {
+ includePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoveragePaths, "+", ",")
+ excludePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoverageExcludePaths, "-", ",")
+ if len(includePaths) > 0 && len(excludePaths) > 0 {
+ includePaths += ","
+ }
+ coverageFlags = append(coverageFlags, fmt.Sprintf(`--instrumentation_filter=%s`,
+ includePaths+excludePaths))
+ }
+ }
+
+ extraFlags := append([]string{"--output=jsonproto"}, coverageFlags...)
+
aqueryOutput, _, err = context.issueBazelCommand(
context.paths,
bazel.AqueryBuildRootRunName,
bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
// proto sources, which would add a number of unnecessary dependencies.
- "--output=jsonproto")
+ extraFlags...)
if err != nil {
return err
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index cfdccd7..dd9a7ed 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -4,11 +4,14 @@
"os"
"path/filepath"
"reflect"
+ "strings"
"testing"
"android/soong/bazel/cquery"
)
+var testConfig = TestConfig("out", nil, "", nil)
+
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
label := "//foo:bar"
cfg := configKey{"arm64_armv8-a", Android}
@@ -16,7 +19,7 @@
bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
})
bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
- err := bazelContext.InvokeBazel()
+ err := bazelContext.InvokeBazel(testConfig)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -30,7 +33,7 @@
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
- err := bazelContext.InvokeBazel()
+ err := bazelContext.InvokeBazel(testConfig)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -86,7 +89,7 @@
}]
}`,
})
- err := bazelContext.InvokeBazel()
+ err := bazelContext.InvokeBazel(testConfig)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -97,6 +100,54 @@
}
}
+func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
+ testConfig.productVariables.ClangCoverage = boolPtr(true)
+
+ testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
+ testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
+ verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
+
+ testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
+ testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
+ verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
+
+ testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
+ testConfig.productVariables.NativeCoverageExcludePaths = nil
+ verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
+
+ testConfig.productVariables.NativeCoveragePaths = nil
+ testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
+ verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
+
+ testConfig.productVariables.ClangCoverage = boolPtr(false)
+ actual := verifyExtraFlags(t, testConfig, ``)
+ if strings.Contains(actual, "--collect_code_coverage") ||
+ strings.Contains(actual, "--instrumentation_filter=") {
+ t.Errorf("Expected code coverage disabled, but got %#v", actual)
+ }
+}
+
+func verifyExtraFlags(t *testing.T, config Config, expected string) string {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+ err := bazelContext.InvokeBazel(config)
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+
+ flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
+ if expected := 3; len(flags) != expected {
+ t.Errorf("Expected %d extra flags got %#v", expected, flags)
+ }
+
+ actual := flags[1]
+ if !strings.Contains(actual, expected) {
+ t.Errorf("Expected %#v got %#v", expected, actual)
+ }
+
+ return actual
+}
+
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
t.Helper()
p := bazelPaths{
diff --git a/android/deapexer.go b/android/deapexer.go
index 265f531..6a93f60 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,6 +15,8 @@
package android
import (
+ "strings"
+
"github.com/google/blueprint"
)
@@ -148,12 +150,19 @@
func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
var di *DeapexerInfo
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
- p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ p := &c
if di != nil {
+ // If two DeapexerInfo providers have been found then check if they are
+ // equivalent. If they are then use the selected one, otherwise fail.
+ if selected := equivalentDeapexerInfoProviders(di, p); selected != nil {
+ di = selected
+ return
+ }
ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
di.ApexModuleName(), p.ApexModuleName())
}
- di = &p
+ di = p
})
if di != nil {
return di
@@ -162,3 +171,33 @@
ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
return nil
}
+
+// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
+func removeCompressedApexSuffix(name string) string {
+ return strings.TrimSuffix(name, "_compressed")
+}
+
+// equivalentDeapexerInfoProviders checks to make sure that the two DeapexerInfo structures are
+// equivalent.
+//
+// At the moment <x> and <x>_compressed APEXes are treated as being equivalent.
+//
+// If they are not equivalent then this returns nil, otherwise, this returns the DeapexerInfo that
+// should be used by the build, which is always the uncompressed one. That ensures that the behavior
+// of the build is not dependent on which prebuilt APEX is visited first.
+func equivalentDeapexerInfoProviders(p1 *DeapexerInfo, p2 *DeapexerInfo) *DeapexerInfo {
+ n1 := removeCompressedApexSuffix(p1.ApexModuleName())
+ n2 := removeCompressedApexSuffix(p2.ApexModuleName())
+
+ // If the names don't match then they are not equivalent.
+ if n1 != n2 {
+ return nil
+ }
+
+ // Select the uncompressed APEX.
+ if n1 == removeCompressedApexSuffix(n1) {
+ return p1
+ } else {
+ return p2
+ }
+}
diff --git a/android/gen_notice.go b/android/gen_notice.go
index fda91ac..e2b839f 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -67,7 +67,12 @@
if ctx.Failed() {
return
}
- out(ctx, gm.output, ctx.ModuleName(gm), proptools.StringDefault(gm.properties.ArtifactName, defaultName), "", modules...)
+ out(ctx, gm.output, ctx.ModuleName(gm),
+ proptools.StringDefault(gm.properties.ArtifactName, defaultName),
+ []string{
+ ctx.Config().OutDir() + "/",
+ ctx.Config().SoongOutDir() + "/",
+ }, modules...)
})
}
diff --git a/android/module.go b/android/module.go
index ad01e9e..2925081 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1177,7 +1177,6 @@
data := &attrs.Data
- required := depsToLabelList(props.Required)
archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
var enabledProperty bazel.BoolAttribute
@@ -1231,10 +1230,21 @@
}
}
+ required := depsToLabelList(props.Required)
for axis, configToProps := range archVariantProps {
for config, _props := range configToProps {
if archProps, ok := _props.(*commonProperties); ok {
- required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
+ // TODO(b/234748998) Remove this requiredFiltered workaround when aapt2 converts successfully
+ requiredFiltered := archProps.Required
+ if name == "apexer" {
+ requiredFiltered = make([]string, 0, len(archProps.Required))
+ for _, req := range archProps.Required {
+ if req != "aapt2" && req != "apexer" {
+ requiredFiltered = append(requiredFiltered, req)
+ }
+ }
+ }
+ required.SetSelectValue(axis, config, depsToLabelList(requiredFiltered).Value)
if !neitherHostNorDevice {
if archProps.Enabled != nil {
if axis != bazel.OsConfigurationAxis || osSupport[config] {
diff --git a/android/notices.go b/android/notices.go
index 562a156..b9c1682 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -47,7 +47,9 @@
}
// buildNoticeOutputFromLicenseMetadata writes out a notice file.
-func buildNoticeOutputFromLicenseMetadata(ctx BuilderContext, tool, ruleName string, outputFile WritablePath, libraryName, stripPrefix string, modules ...Module) {
+func buildNoticeOutputFromLicenseMetadata(
+ ctx BuilderContext, tool, ruleName string, outputFile WritablePath,
+ libraryName string, stripPrefix []string, modules ...Module) {
depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
rule := NewRuleBuilder(pctx, ctx)
if len(modules) == 0 {
@@ -64,8 +66,8 @@
BuiltTool(tool).
FlagWithOutput("-o ", outputFile).
FlagWithDepFile("-d ", depsFile)
- if stripPrefix != "" {
- cmd = cmd.FlagWithArg("--strip_prefix ", stripPrefix)
+ if len(stripPrefix) > 0 {
+ cmd = cmd.FlagForEachArg("--strip_prefix ", stripPrefix)
}
outputs := modulesOutputDirs(ctx, modules...)
if len(outputs) > 0 {
@@ -81,20 +83,29 @@
// BuildNoticeTextOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeTextOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeTextOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
// BuildNoticeHtmlOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeHtmlOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
// BuildNoticeXmlOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeXmlOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeXmlOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
diff --git a/android/util.go b/android/util.go
index 47c4583..a0f7160 100644
--- a/android/util.go
+++ b/android/util.go
@@ -32,6 +32,12 @@
// JoinWithPrefix prepends the prefix to each string in the list and
// returns them joined together with " " as separator.
func JoinWithPrefix(strs []string, prefix string) string {
+ return JoinWithPrefixAndSeparator(strs, prefix, " ")
+}
+
+// JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
if len(strs) == 0 {
return ""
}
@@ -40,7 +46,7 @@
buf.WriteString(prefix)
buf.WriteString(strs[0])
for i := 1; i < len(strs); i++ {
- buf.WriteString(" ")
+ buf.WriteString(sep)
buf.WriteString(prefix)
buf.WriteString(strs[i])
}
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 9519be0..280dae8 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -124,7 +124,12 @@
s.CopySpecsToDir(ctx, builder, packageSpecs, dir)
noticeFile := android.PathForModuleOut(ctx, "NOTICES.txt")
- android.BuildNoticeTextOutputFromLicenseMetadata(ctx, noticeFile, "", "", outputZipFile.String())
+ android.BuildNoticeTextOutputFromLicenseMetadata(
+ ctx, noticeFile, "", "",
+ []string{
+ android.PathForModuleInstall(ctx, "sdk-repo").String() + "/",
+ outputZipFile.String(),
+ })
builder.Command().Text("cp").
Input(noticeFile).
Text(filepath.Join(dir.String(), "NOTICE.txt"))
diff --git a/apex/apex.go b/apex/apex.go
index 64e1760..beabbc9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2548,6 +2548,11 @@
if overridableProperties.Package_name != "" {
attrs.Package_name = &overridableProperties.Package_name
}
+
+ // Logging parent
+ if overridableProperties.Logging_parent != "" {
+ attrs.Logging_parent = &overridableProperties.Logging_parent
+ }
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: o.Name()}, &attrs)
@@ -3490,6 +3495,7 @@
Native_shared_libs_64 bazel.LabelListAttribute
Compressible bazel.BoolAttribute
Package_name *string
+ Logging_parent *string
}
type convertedNativeSharedLibs struct {
@@ -3589,6 +3595,11 @@
packageName = &a.overridableProperties.Package_name
}
+ var loggingParent *string
+ if a.overridableProperties.Logging_parent != "" {
+ loggingParent = &a.overridableProperties.Logging_parent
+ }
+
attrs := bazelApexBundleAttributes{
Manifest: manifestLabelAttribute,
Android_manifest: androidManifestLabelAttribute,
@@ -3604,6 +3615,7 @@
Prebuilts: prebuiltsLabelListAttribute,
Compressible: compressibleAttribute,
Package_name: packageName,
+ Logging_parent: loggingParent,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7905710..dbe9180 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7440,7 +7440,7 @@
return result.TestContext
}
-func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) {
+func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
preparers := android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
PrepareForTestWithApexBuildComponents,
@@ -7509,6 +7509,107 @@
})
}
+func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ )
+
+ bpBase := `
+ apex_set {
+ name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "myapex.apks",
+ }
+
+ apex_set {
+ name: "com.android.myapex_compressed",
+ apex_name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "myapex_compressed.apks",
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "my-bootclasspath-fragment",
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ hidden_api: {
+ annotation_flags: "annotation-flags.csv",
+ metadata: "metadata.csv",
+ index: "index.csv",
+ signature_patterns: "signature_patterns.csv",
+ },
+ %s
+ }
+ `
+
+ t.Run("java_import", func(t *testing.T) {
+ result := preparers.RunTestWithBp(t,
+ fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ }
+ `)
+
+ module := result.Module("libfoo", "android_common_com.android.myapex")
+ usesLibraryDep := module.(java.UsesLibraryDependency)
+ android.AssertPathRelativeToTopEquals(t, "dex jar path",
+ "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+ usesLibraryDep.DexJarBuildPath().Path())
+ })
+
+ t.Run("java_sdk_library_import", func(t *testing.T) {
+ result := preparers.RunTestWithBp(t,
+ fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ compile_dex: true,
+ }
+ `)
+
+ module := result.Module("libfoo", "android_common_com.android.myapex")
+ usesLibraryDep := module.(java.UsesLibraryDependency)
+ android.AssertPathRelativeToTopEquals(t, "dex jar path",
+ "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+ usesLibraryDep.DexJarBuildPath().Path())
+ })
+
+ t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
+ _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
+ image_name: "art",
+ contents: ["libfoo"],
+ `)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ compile_dex: true,
+ }
+ `)
+ })
+}
+
func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
apex {
diff --git a/apex/builder.go b/apex/builder.go
index 73e9b73..fc9bb3b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -618,7 +618,12 @@
// Create a NOTICE file, and embed it as an asset file in the APEX.
a.htmlGzNotice = android.PathForModuleOut(ctx, "NOTICE.html.gz")
- android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, a.htmlGzNotice, "", "", unsignedOutputFile.String())
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, a.htmlGzNotice, "", "",
+ []string{
+ android.PathForModuleInstall(ctx).String() + "/",
+ android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
+ })
noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 433d502..5e4ebf8 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -664,6 +664,9 @@
if a.Mnemonic == "FileWrite" {
return true
}
+ if a.Mnemonic == "BaselineCoverage" {
+ return true
+ }
return false
}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 5d00b0b..f5435f2 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -132,7 +132,7 @@
sharedLibraries = []
rootSharedLibraries = []
-shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
+shared_info_tag = "@_builtins//:common/cc/experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
if shared_info_tag in providers(target):
shared_info = providers(target)[shared_info_tag]
for lib in shared_info.linker_input.libraries:
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 05045ee..7bc379f 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -137,6 +137,7 @@
"prebuilt_2",
],
package_name: "com.android.apogee.test.package",
+ logging_parent: "logging.parent",
}
`,
expectedBazelTargets: []string{
@@ -171,9 +172,10 @@
":prebuilt_1",
":prebuilt_2",
]`,
- "updatable": "False",
- "compressible": "False",
- "package_name": `"com.android.apogee.test.package"`,
+ "updatable": "False",
+ "compressible": "False",
+ "package_name": `"com.android.apogee.test.package"`,
+ "logging_parent": `"logging.parent"`,
}),
}})
}
@@ -945,3 +947,72 @@
}),
}})
}
+
+func TestApexBundleSimple_NoLoggingParentOverride(t *testing.T) {
+ runOverrideApexTestCase(t, bp2buildTestCase{
+ description: "override_apex - logging_parent - no override",
+ moduleTypeUnderTest: "override_apex",
+ moduleTypeUnderTestFactory: apex.OverrideApexFactory,
+ filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ blueprint: `
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ logging_parent: "foo.bar.baz",
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "logging_parent": `"foo.bar.baz"`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_LoggingParentOverride(t *testing.T) {
+ runOverrideApexTestCase(t, bp2buildTestCase{
+ description: "override_apex - logging_parent - override",
+ moduleTypeUnderTest: "override_apex",
+ moduleTypeUnderTestFactory: apex.OverrideApexFactory,
+ filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ blueprint: `
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ logging_parent: "foo.bar.baz",
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+ logging_parent: "foo.bar.baz.override",
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "logging_parent": `"foo.bar.baz.override"`,
+ }),
+ }})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 555f5a7..2cc2207 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -959,11 +959,12 @@
"features": `[
"disable_pack_relocations",
"-no_undefined_symbols",
+ "-coverage",
]`,
"srcs": `["a.cpp"]`,
})...)
expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
- "features": `select({
+ "features": `["-coverage"] + select({
"//build/bazel/platforms/arch:x86_64": [
"disable_pack_relocations",
"-no_undefined_symbols",
@@ -994,6 +995,7 @@
pack_relocations: false,
allow_undefined_symbols: true,
include_build_directory: false,
+ native_coverage: false,
}
cc_library {
@@ -1006,6 +1008,7 @@
},
},
include_build_directory: false,
+ native_coverage: false,
}
cc_library {
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index dfa11d1..22bd028 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -43,9 +43,10 @@
}`,
expectedBazelTargets: []string{
makeBazelTarget("py_binary", "foo", attrNameToString{
- "data": `["files/data.txt"]`,
- "deps": `[":bar"]`,
- "main": `"a.py"`,
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "main": `"a.py"`,
+ "imports": `["."]`,
"srcs": `[
"a.py",
"b/c.py",
@@ -83,6 +84,7 @@
expectedBazelTargets: []string{
makeBazelTarget("py_binary", "foo", attrNameToString{
"python_version": `"PY2"`,
+ "imports": `["."]`,
"srcs": `["a.py"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -116,7 +118,8 @@
expectedBazelTargets: []string{
// python_version is PY3 by default.
makeBazelTarget("py_binary", "foo", attrNameToString{
- "srcs": `["a.py"]`,
+ "imports": `["."]`,
+ "srcs": `["a.py"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -148,6 +151,7 @@
}`,
expectedBazelTargets: []string{
makeBazelTarget("py_binary", "foo-arm", attrNameToString{
+ "imports": `["."]`,
"srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 70dcf40..d891007 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -55,6 +55,8 @@
Enabled bazel.BoolAttribute
+ Native_coverage bazel.BoolAttribute
+
sdkAttributes
}
@@ -568,10 +570,15 @@
}
}
}
-
compilerAttrs.convertStlProps(ctx, module)
(&linkerAttrs).convertStripProps(ctx, module)
+ if module.coverage != nil && module.coverage.Properties.Native_coverage != nil &&
+ !Bool(module.coverage.Properties.Native_coverage) {
+ // Native_coverage is arch neutral
+ (&linkerAttrs).features.Append(bazel.MakeStringListAttribute([]string{"-coverage"}))
+ }
+
productVariableProps := android.ProductVariableProperties(ctx)
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index fb24624..38f6383 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4076,7 +4076,7 @@
{
name: "assemble",
src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__"}, expectedIncludes, lastIncludes),
+ expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__", "-fdebug-default-version=4"}, expectedIncludes, lastIncludes),
},
}
diff --git a/cc/compiler.go b/cc/compiler.go
index c7e9c9a..cd1d92c 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -495,6 +495,10 @@
flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
+ // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
+ // end up in the dwarf data for crtend_so.S.
+ flags.Global.AsFlags = append(flags.Global.AsFlags, "-fdebug-default-version=4")
+
flags.Global.CppFlags = append(flags.Global.CppFlags, tc.Cppflags())
flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 826197a..674edad 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -19,6 +19,37 @@
"strings"
)
+var (
+ // Some clang-tidy checks have bugs or don't work for Android.
+ // They are disabled here, overriding any locally selected checks.
+ globalNoCheckList = []string{
+ // https://b.corp.google.com/issues/153464409
+ // many local projects enable cert-* checks, which
+ // trigger bugprone-reserved-identifier.
+ "-bugprone-reserved-identifier*,-cert-dcl51-cpp,-cert-dcl37-c",
+ // http://b/153757728
+ "-readability-qualified-auto",
+ // http://b/193716442
+ "-bugprone-implicit-widening-of-multiplication-result",
+ // Too many existing functions trigger this rule, and fixing it requires large code
+ // refactoring. The cost of maintaining this tidy rule outweighs the benefit it brings.
+ "-bugprone-easily-swappable-parameters",
+ // http://b/216364337 - TODO: Follow-up after compiler update to
+ // disable or fix individual instances.
+ "-cert-err33-c",
+ }
+
+ // Some clang-tidy checks are included in some tidy_checks_as_errors lists,
+ // but not all warnings are fixed/suppressed yet. These checks are not
+ // disabled in the TidyGlobalNoChecks list, so we can see them and fix/suppress them.
+ globalNoErrorCheckList = []string{
+ // http://b/155034563
+ "-bugprone-signed-char-misuse",
+ // http://b/155034972
+ "-bugprone-branch-clone",
+ }
+)
+
func init() {
// Many clang-tidy checks like altera-*, llvm-*, modernize-*
// are not designed for Android source code or creating too
@@ -94,6 +125,14 @@
}, ",")
})
+ pctx.VariableFunc("TidyGlobalNoChecks", func(ctx android.PackageVarContext) string {
+ return strings.Join(globalNoCheckList, ",")
+ })
+
+ pctx.VariableFunc("TidyGlobalNoErrorChecks", func(ctx android.PackageVarContext) string {
+ return strings.Join(globalNoErrorCheckList, ",")
+ })
+
// To reduce duplicate warnings from the same header files,
// header-filter will contain only the module directory and
// those specified by DEFAULT_TIDY_HEADER_DIRS.
@@ -152,6 +191,22 @@
return tidyDefault
}
+// Returns a globally disabled tidy checks, overriding locally selected checks.
+func TidyGlobalNoChecks() string {
+ if len(globalNoCheckList) > 0 {
+ return ",${config.TidyGlobalNoChecks}"
+ }
+ return ""
+}
+
+// Returns a globally allowed/no-error tidy checks, appended to -warnings-as-errors.
+func TidyGlobalNoErrorChecks() string {
+ if len(globalNoErrorCheckList) > 0 {
+ return ",${config.TidyGlobalNoErrorChecks}"
+ }
+ return ""
+}
+
func TidyFlagsForSrcFile(srcFile android.Path, flags string) string {
// Disable clang-analyzer-* checks globally for generated source files
// because some of them are too huge. Local .bp files can add wanted
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 8cf61fa..42a112e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -722,6 +722,11 @@
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
}
+ if enableMinimalRuntime(sanitize) {
+ flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+ }
+
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
// When fuzzing, we wish to crash with diagnostics on any bug.
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
@@ -730,12 +735,6 @@
} else {
flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
}
-
- if enableMinimalRuntime(sanitize) {
- flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
- }
-
// http://b/119329758, Android core does not boot up with this sanitizer yet.
if toDisableImplicitIntegerChange(flags.Local.CFlags) {
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
diff --git a/cc/tidy.go b/cc/tidy.go
index e8e1783..6b5d572 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -15,6 +15,7 @@
package cc
import (
+ "fmt"
"path/filepath"
"regexp"
"strings"
@@ -62,6 +63,11 @@
return []interface{}{&tidy.Properties}
}
+// Set this const to true when all -warnings-as-errors in tidy_flags
+// are replaced with tidy_checks_as_errors.
+// Then, that old style usage will be obsolete and an error.
+const NoWarningsAsErrorsInTidyFlags = true
+
func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
@@ -160,43 +166,38 @@
tidyChecks = tidyChecks + "," + strings.Join(esc(ctx, "tidy_checks",
config.ClangRewriteTidyChecks(localChecks)), ",")
}
-
}
+ tidyChecks = tidyChecks + config.TidyGlobalNoChecks()
if ctx.Windows() {
// https://b.corp.google.com/issues/120614316
// mingw32 has cert-dcl16-c warning in NO_ERROR,
// which is used in many Android files.
- tidyChecks = tidyChecks + ",-cert-dcl16-c"
+ tidyChecks += ",-cert-dcl16-c"
}
- // https://b.corp.google.com/issues/153464409
- // many local projects enable cert-* checks, which
- // trigger bugprone-reserved-identifier.
- tidyChecks = tidyChecks + ",-bugprone-reserved-identifier*,-cert-dcl51-cpp,-cert-dcl37-c"
- // http://b/153757728
- tidyChecks = tidyChecks + ",-readability-qualified-auto"
- // http://b/155034563
- tidyChecks = tidyChecks + ",-bugprone-signed-char-misuse"
- // http://b/155034972
- tidyChecks = tidyChecks + ",-bugprone-branch-clone"
- // http://b/193716442
- tidyChecks = tidyChecks + ",-bugprone-implicit-widening-of-multiplication-result"
- // Too many existing functions trigger this rule, and fixing it requires large code
- // refactoring. The cost of maintaining this tidy rule outweighs the benefit it brings.
- tidyChecks = tidyChecks + ",-bugprone-easily-swappable-parameters"
- // http://b/216364337 - TODO: Follow-up after compiler update to
- // disable or fix individual instances.
- tidyChecks = tidyChecks + ",-cert-err33-c"
+
flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
// Embedding -warnings-as-errors in tidy_flags is error-prone.
// It should be replaced with the tidy_checks_as_errors list.
- for _, s := range flags.TidyFlags {
+ for i, s := range flags.TidyFlags {
if strings.Contains(s, "-warnings-as-errors=") {
- ctx.PropertyErrorf("tidy_flags", "should not contain -warnings-as-errors, use tidy_checks_as_errors instead")
+ if NoWarningsAsErrorsInTidyFlags {
+ ctx.PropertyErrorf("tidy_flags", "should not contain "+s+"; use tidy_checks_as_errors instead.")
+ } else {
+ fmt.Printf("%s: warning: module %s's tidy_flags should not contain %s, which is replaced with -warnings-as-errors=-*; use tidy_checks_as_errors for your own as-error warnings instead.\n",
+ ctx.BlueprintsFile(), ctx.ModuleName(), s)
+ flags.TidyFlags[i] = "-warnings-as-errors=-*"
+ }
+ break // there is at most one -warnings-as-errors
}
}
+ // Default clang-tidy flags does not contain -warning-as-errors.
+ // If a module has tidy_checks_as_errors, add the list to -warnings-as-errors
+ // and then append the TidyGlobalNoErrorChecks.
if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
- tidyChecksAsErrors := "-warnings-as-errors=" + strings.Join(esc(ctx, "tidy_checks_as_errors", tidy.Properties.Tidy_checks_as_errors), ",")
+ tidyChecksAsErrors := "-warnings-as-errors=" +
+ strings.Join(esc(ctx, "tidy_checks_as_errors", tidy.Properties.Tidy_checks_as_errors), ",") +
+ config.TidyGlobalNoErrorChecks()
flags.TidyFlags = append(flags.TidyFlags, tidyChecksAsErrors)
}
return flags
diff --git a/cc/tidy_test.go b/cc/tidy_test.go
index 5863a6c..7036ecb 100644
--- a/cc/tidy_test.go
+++ b/cc/tidy_test.go
@@ -24,12 +24,14 @@
func TestTidyFlagsWarningsAsErrors(t *testing.T) {
// The "tidy_flags" property should not contain -warnings-as-errors.
- testCases := []struct {
+ type testCase struct {
libName, bp string
errorMsg string // a negative test; must have error message
flags []string // must have substrings in tidyFlags
noFlags []string // must not have substrings in tidyFlags
- }{
+ }
+
+ testCases := []testCase{
{
"libfoo1",
`cc_library_shared { // no warnings-as-errors, good tidy_flags
@@ -47,27 +49,31 @@
name: "libfoo2",
srcs: ["foo.c"],
tidy_checks_as_errors: ["xyz-*", "abc"],
- tidy_flags: ["-header-filter=dir2/"],
}`,
"",
- []string{"-header-filter=dir2/", "-warnings-as-errors='xyz-*',abc"},
+ []string{
+ "-header-filter=^", // there is a default header filter
+ "-warnings-as-errors='xyz-*',abc,${config.TidyGlobalNoErrorChecks}",
+ },
[]string{},
},
- {
+ }
+ if NoWarningsAsErrorsInTidyFlags {
+ testCases = append(testCases, testCase{
"libfoo3",
`cc_library_shared { // bad use of -warnings-as-errors in tidy_flags
- name: "libfoo3",
- srcs: ["foo.c"],
- tidy_flags: [
- "-header-filters=.*",
- "-warnings-as-errors=xyz-*",
- ],
- }`,
- `module "libfoo3" .*: tidy_flags: should not contain -warnings-as-errors,` +
+ name: "libfoo3",
+ srcs: ["foo.c"],
+ tidy_flags: [
+ "-header-filters=.*",
+ "-warnings-as-errors=xyz-*",
+ ],
+ }`,
+ `module "libfoo3" .*: tidy_flags: should not contain .*;` +
` use tidy_checks_as_errors instead`,
[]string{},
[]string{},
- },
+ })
}
for _, test := range testCases {
if test.errorMsg != "" {
@@ -80,12 +86,12 @@
flags := ctx.ModuleForTests(test.libName, variant).Rule("clangTidy").Args["tidyFlags"]
for _, flag := range test.flags {
if !strings.Contains(flags, flag) {
- t.Errorf("tidyFlags for %s does not contain %s.", test.libName, flag)
+ t.Errorf("tidyFlags %v for %s does not contain %s.", flags, test.libName, flag)
}
}
for _, flag := range test.noFlags {
if strings.Contains(flags, flag) {
- t.Errorf("tidyFlags for %s should not contain %s.", test.libName, flag)
+ t.Errorf("tidyFlags %v for %s should not contain %s.", flags, test.libName, flag)
}
}
})
@@ -122,7 +128,7 @@
firstXyzChecks := "-checks='-*','xyz-*',"
localXyzChecks := "'-*','xyz-*'"
localAbcChecks := "'-abc*','xyz-*',mycheck"
- extraGlobalChecks := ",-bugprone-easily-swappable-parameters,"
+ extraGlobalChecks := ",${config.TidyGlobalNoChecks}"
testCases := []struct {
libNumber int // 1,2,3,...
checks []string // must have substrings in -checks
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index c548ef8..8a3d6e0 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -139,7 +139,7 @@
bazelHook := func() error {
ctx.EventHandler.Begin("bazel")
defer ctx.EventHandler.End("bazel")
- return configuration.BazelContext.InvokeBazel()
+ return configuration.BazelContext.InvokeBazel(configuration)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 857dfa7..dfcd405 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -12,6 +12,7 @@
"soong-linkerconfig",
],
srcs: [
+ "avb_add_hash_footer.go",
"bootimg.go",
"filesystem.go",
"logical_partition.go",
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
new file mode 100644
index 0000000..af3bdbe
--- /dev/null
+++ b/filesystem/avb_add_hash_footer.go
@@ -0,0 +1,149 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// 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 filesystem
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory)
+}
+
+type avbAddHashFooter struct {
+ android.ModuleBase
+
+ properties avbAddHashFooterProperties
+
+ output android.OutputPath
+ installDir android.InstallPath
+}
+
+type avbAddHashFooterProperties struct {
+ // Source file of this image. Can reference a genrule type module with the ":module" syntax.
+ Src *string `android:"path,arch_variant"`
+
+ // Set the name of the output. Defaults to <module_name>.img.
+ Filename *string
+
+ // Name of the image partition. Defaults to the name of this module.
+ Partition_name *string
+
+ // Size of the partition. Defaults to dynamically calculating the size.
+ Partition_size *int64
+
+ // Path to the private key that avbtool will use to sign this image.
+ Private_key *string `android:"path"`
+
+ // Algorithm that avbtool will use to sign this image. Default is SHA256_RSA4096.
+ Algorithm *string
+
+ // The salt in hex. Required for reproducible builds.
+ Salt *string
+}
+
+// The AVB footer adds verification information to the image.
+func avbAddHashFooterFactory() android.Module {
+ module := &avbAddHashFooter{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
+func (a *avbAddHashFooter) installFileName() string {
+ return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".img")
+}
+
+func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ builder := android.NewRuleBuilder(pctx, ctx)
+
+ if a.properties.Src == nil {
+ ctx.PropertyErrorf("src", "missing source file")
+ return
+ }
+ input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src))
+ a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
+ builder.Command().Text("cp").Input(input).Output(a.output)
+
+ cmd := builder.Command().BuiltTool("avbtool").Text("add_hash_footer")
+
+ partition_name := proptools.StringDefault(a.properties.Partition_name, a.BaseModuleName())
+ cmd.FlagWithArg("--partition_name ", partition_name)
+
+ if a.properties.Partition_size == nil {
+ cmd.Flag("--dynamic_partition_size")
+ } else {
+ partition_size := proptools.Int(a.properties.Partition_size)
+ cmd.FlagWithArg("--partition_size ", strconv.Itoa(partition_size))
+ }
+
+ key := android.PathForModuleSrc(ctx, proptools.String(a.properties.Private_key))
+ cmd.FlagWithInput("--key ", key)
+
+ algorithm := proptools.StringDefault(a.properties.Algorithm, "SHA256_RSA4096")
+ cmd.FlagWithArg("--algorithm ", algorithm)
+
+ if a.properties.Salt == nil {
+ ctx.PropertyErrorf("salt", "missing salt value")
+ return
+ }
+ cmd.FlagWithArg("--salt ", proptools.String(a.properties.Salt))
+
+ cmd.FlagWithOutput("--image ", a.output)
+
+ builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
+
+ a.installDir = android.PathForModuleInstall(ctx, "etc")
+ ctx.InstallFile(a.installDir, a.installFileName(), a.output)
+}
+
+var _ android.AndroidMkEntriesProvider = (*avbAddHashFooter)(nil)
+
+// Implements android.AndroidMkEntriesProvider
+func (a *avbAddHashFooter) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(a.output),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", a.installDir.String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", a.installFileName())
+ },
+ },
+ }}
+}
+
+var _ Filesystem = (*avbAddHashFooter)(nil)
+
+func (a *avbAddHashFooter) OutputPath() android.Path {
+ return a.output
+}
+
+func (a *avbAddHashFooter) SignedOutputPath() android.Path {
+ return a.OutputPath() // always signed
+}
+
+// TODO(b/185115783): remove when not needed as input to a prebuilt_etc rule
+var _ android.SourceFileProducer = (*avbAddHashFooter)(nil)
+
+// Implements android.SourceFileProducer
+func (a *avbAddHashFooter) Srcs() android.Paths {
+ return append(android.Paths{}, a.output)
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 818e1bc..2a80563 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -266,7 +266,7 @@
var bazelOutputFiles android.Paths
exportIncludeDirs := map[string]bool{}
for _, bazelOutputFile := range filePaths {
- bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOut(ctx, bazelOutputFile))
+ bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), bazelOutputFile))
exportIncludeDirs[filepath.Dir(bazelOutputFile)] = true
}
g.outputFiles = bazelOutputFiles
diff --git a/java/app.go b/java/app.go
index c61c4e5..c5d88e9 100755
--- a/java/app.go
+++ b/java/app.go
@@ -656,7 +656,13 @@
if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
- android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, noticeFile, "", "", a.outputFile.String())
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, noticeFile, "", "",
+ []string{
+ a.installDir.String() + "/",
+ android.PathForModuleInstall(ctx).String() + "/",
+ a.outputFile.String(),
+ })
noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index e59146b..2707f0c 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -830,21 +830,13 @@
pathPattern = append(pathPattern, chunk)
}
}
- if pathPattern[0] == "" && len(ctx.includeTops) > 0 {
- // If pattern starts from the top. restrict it to the directories where
- // we know inherit-product uses dynamically calculated path.
- for _, p := range ctx.includeTops {
- pathPattern[0] = p
- matchingPaths = append(matchingPaths, ctx.findMatchingPaths(pathPattern)...)
- }
- } else {
- matchingPaths = ctx.findMatchingPaths(pathPattern)
+ if len(pathPattern) == 1 {
+ pathPattern = append(pathPattern, "")
}
+ matchingPaths = ctx.findMatchingPaths(pathPattern)
needsWarning = pathPattern[0] == "" && len(ctx.includeTops) == 0
} else if len(ctx.includeTops) > 0 {
- for _, p := range ctx.includeTops {
- matchingPaths = append(matchingPaths, ctx.findMatchingPaths([]string{p, ""})...)
- }
+ matchingPaths = append(matchingPaths, ctx.findMatchingPaths([]string{"", ""})...)
} else {
return []starlarkNode{ctx.newBadNode(v, "inherit-product/include argument is too complex")}
}
@@ -872,17 +864,31 @@
}
// Create regular expression from the pattern
- s_regexp := "^" + regexp.QuoteMeta(pattern[0])
+ regexString := "^" + regexp.QuoteMeta(pattern[0])
for _, s := range pattern[1:] {
- s_regexp += ".*" + regexp.QuoteMeta(s)
+ regexString += ".*" + regexp.QuoteMeta(s)
}
- s_regexp += "$"
- rex := regexp.MustCompile(s_regexp)
+ regexString += "$"
+ rex := regexp.MustCompile(regexString)
+
+ includeTopRegexString := ""
+ if len(ctx.includeTops) > 0 {
+ for i, top := range ctx.includeTops {
+ if i > 0 {
+ includeTopRegexString += "|"
+ }
+ includeTopRegexString += "^" + regexp.QuoteMeta(top)
+ }
+ } else {
+ includeTopRegexString = ".*"
+ }
+
+ includeTopRegex := regexp.MustCompile(includeTopRegexString)
// Now match
var res []string
for _, p := range files {
- if rex.MatchString(p) {
+ if rex.MatchString(p) && includeTopRegex.MatchString(p) {
res = append(res, p)
}
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index a09764c..31555d3 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1157,6 +1157,8 @@
#RBC# include_top vendor/foo1
$(call inherit-product,$(MY_OTHER_PATH))
#RBC# include_top vendor/foo1
+$(call inherit-product,vendor/$(MY_OTHER_PATH))
+#RBC# include_top vendor/foo1
$(foreach f,$(MY_MAKEFILES), \
$(call inherit-product,$(f)))
`,
@@ -1180,6 +1182,13 @@
if not _varmod_init:
rblf.mkerror("product.mk", "Cannot find %s" % (g.get("MY_OTHER_PATH", "")))
rblf.inherit(handle, _varmod, _varmod_init)
+ _entry = {
+ "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
+ }.get("vendor/%s" % g.get("MY_OTHER_PATH", ""))
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("vendor/%s" % g.get("MY_OTHER_PATH", "")))
+ rblf.inherit(handle, _varmod, _varmod_init)
for f in rblf.words(g.get("MY_MAKEFILES", "")):
_entry = {
"vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
diff --git a/python/binary.go b/python/binary.go
index 99c6259..af29bb6 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -38,6 +38,7 @@
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Python_version *string
+ Imports bazel.StringListAttribute
}
func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
@@ -75,6 +76,7 @@
Srcs: baseAttrs.Srcs,
Deps: baseAttrs.Deps,
Python_version: python_version,
+ Imports: baseAttrs.Imports,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/python/library.go b/python/library.go
index 5071b74..df92df4 100644
--- a/python/library.go
+++ b/python/library.go
@@ -17,9 +17,6 @@
// This file contains the module types for building Python library.
import (
- "path/filepath"
- "strings"
-
"android/soong/android"
"android/soong/bazel"
@@ -72,40 +69,13 @@
// do nothing, since python_version defaults to PY2ANDPY3
}
- // Bazel normally requires `import path.from.top.of.tree` statements in
- // python code, but with soong you can directly import modules from libraries.
- // Add "imports" attributes to the bazel library so it matches soong's behavior.
- imports := "."
- if m.properties.Pkg_path != nil {
- // TODO(b/215119317) This is a hack to handle the fact that we don't convert
- // pkg_path properly right now. If the folder structure that contains this
- // Android.bp file matches pkg_path, we can set imports to an appropriate
- // number of ../..s to emulate moving the files under a pkg_path folder.
- pkg_path := filepath.Clean(*m.properties.Pkg_path)
- if strings.HasPrefix(pkg_path, "/") {
- ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
- return
- }
-
- if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
- ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
- return
- }
- numFolders := strings.Count(pkg_path, "/") + 1
- dots := make([]string, numFolders)
- for i := 0; i < numFolders; i++ {
- dots[i] = ".."
- }
- imports = strings.Join(dots, "/")
- }
-
baseAttrs := m.makeArchVariantBaseAttributes(ctx)
attrs := &bazelPythonLibraryAttributes{
Srcs: baseAttrs.Srcs,
Deps: baseAttrs.Deps,
Srcs_version: python_version,
- Imports: bazel.MakeStringListAttribute([]string{imports}),
+ Imports: baseAttrs.Imports,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/python/python.go b/python/python.go
index 7e4cb83..eb0d3ca 100644
--- a/python/python.go
+++ b/python/python.go
@@ -131,7 +131,8 @@
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
// Combines Data and Java_data (invariant)
- Data bazel.LabelListAttribute
+ Data bazel.LabelListAttribute
+ Imports bazel.StringListAttribute
}
// Used to store files of current module after expanding dependencies
@@ -230,6 +231,33 @@
attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
}
+
+ // Bazel normally requires `import path.from.top.of.tree` statements in
+ // python code, but with soong you can directly import modules from libraries.
+ // Add "imports" attributes to the bazel library so it matches soong's behavior.
+ imports := "."
+ if m.properties.Pkg_path != nil {
+ // TODO(b/215119317) This is a hack to handle the fact that we don't convert
+ // pkg_path properly right now. If the folder structure that contains this
+ // Android.bp file matches pkg_path, we can set imports to an appropriate
+ // number of ../..s to emulate moving the files under a pkg_path folder.
+ pkg_path := filepath.Clean(*m.properties.Pkg_path)
+ if strings.HasPrefix(pkg_path, "/") {
+ ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
+ }
+
+ if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
+ ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
+ }
+ numFolders := strings.Count(pkg_path, "/") + 1
+ dots := make([]string, numFolders)
+ for i := 0; i < numFolders; i++ {
+ dots[i] = ".."
+ }
+ imports = strings.Join(dots, "/")
+ }
+ attrs.Imports = bazel.MakeStringListAttribute([]string{imports})
+
return attrs
}
@@ -654,7 +682,8 @@
// in order to keep stable order of soong_zip params, we sort the keys here.
roots := android.SortedStringKeys(relativeRootMap)
- parArgs := []string{}
+ // Use -symlinks=false so that the symlinks in the bazel output directory are followed
+ parArgs := []string{"-symlinks=false"}
if pkgPath != "" {
// use package path as path prefix
parArgs = append(parArgs, `-P `+pkgPath)
diff --git a/rust/config/global.go b/rust/config/global.go
index 647a7cf..e9751fd 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.61.0.p1"
+ RustDefaultVersion = "1.61.0.p2"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 0216fc0..c8d4f76 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -20,11 +20,9 @@
import argparse
import json
-import os
import re
import subprocess
import sys
-from collections import OrderedDict
from xml.dom import minidom
from manifest import android_ns
@@ -45,13 +43,11 @@
'--uses-library',
dest='uses_libraries',
action='append',
- default=[],
help='specify uses-library entries known to the build system')
parser.add_argument(
'--optional-uses-library',
dest='optional_uses_libraries',
action='append',
- default=[],
help='specify uses-library entries known to the build system with '
'required:false'
)
@@ -78,14 +74,9 @@
help='print the targetSdkVersion from the manifest')
parser.add_argument(
'--dexpreopt-config',
- dest='dexpreopt_config',
- help='a path to dexpreopt.config file for this library/app')
- parser.add_argument(
- '--dexpreopt-dep-config',
- dest='dexpreopt_dep_configs',
+ dest='dexpreopt_configs',
action='append',
- default=[],
- help='a path to dexpreopt.config file for a dependency library')
+ help='a paths to a dexpreopt.config of some library')
parser.add_argument('--aapt', dest='aapt', help='path to aapt executable')
parser.add_argument(
'--output', '-o', dest='output', help='output AndroidManifest.xml file')
@@ -304,53 +295,25 @@
return target_attr.value
-def remove_duplicates(l):
- return list(OrderedDict.fromkeys(l))
-
-
-def load_dexpreopt_configs(args):
+def load_dexpreopt_configs(configs):
"""Load dexpreopt.config files and map module names to library names."""
module_to_libname = {}
- # Go over dexpreopt.config files for uses-library dependencies and create
- # a mapping from module name to real library name (they may differ).
- for config in args.dexpreopt_dep_configs:
- # Empty dexpreopt.config files are expected for some dependencies.
- if os.stat(config).st_size != 0:
- with open(config, 'r') as f:
- contents = json.load(f)
- module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary']
+ if configs is None:
+ configs = []
- required = translate_libnames(args.uses_libraries, module_to_libname)
- optional = translate_libnames(args.optional_uses_libraries, module_to_libname)
-
- # Add extra uses-libraries from the library/app's own dexpreopt.config.
- # Extra libraries may be propagated via dependencies' dexpreopt.config files
- # (not only uses-library ones, but also transitively via static libraries).
- if args.dexpreopt_config:
- with open(args.dexpreopt_config, 'r') as f:
+ for config in configs:
+ with open(config, 'r') as f:
contents = json.load(f)
- for clc in contents['ClassLoaderContexts']['any']:
- ulib = clc['Name']
- if clc['Optional']:
- optional.append(ulib)
- else:
- required.append(ulib)
+ module_to_libname[contents['Name']] = contents['ProvidesUsesLibrary']
- required = remove_duplicates(required)
- optional = remove_duplicates(optional)
-
- # If the same library is both in optional and required, prefer required.
- # This may happen for compatibility libraries, e.g. org.apache.http.legacy.
- for lib in required:
- if lib in optional:
- optional.remove(lib)
-
- return required, optional
+ return module_to_libname
def translate_libnames(modules, module_to_libname):
"""Translate module names into library names using the mapping."""
+ if modules is None:
+ modules = []
libnames = []
for name in modules:
@@ -383,7 +346,10 @@
# `optional_uses_libs`, `LOCAL_USES_LIBRARIES`,
# `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while
# the manifest addresses libraries by their name.
- required, optional = load_dexpreopt_configs(args)
+ mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs)
+ required = translate_libnames(args.uses_libraries, mod_to_lib)
+ optional = translate_libnames(args.optional_uses_libraries,
+ mod_to_lib)
# Check if the <uses-library> lists in the build system agree with
# those in the manifest. Raise an exception on mismatch, unless the
diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh
index 331dc77..d0d382b 100755
--- a/tests/androidmk_test.sh
+++ b/tests/androidmk_test.sh
@@ -5,7 +5,7 @@
# How to run: bash path-to-script/androidmk_test.sh
# Tests of converting license functionality of the androidmk tool
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
-$REAL_TOP/build/soong/soong_ui.bash --make-mode androidmk
+"$REAL_TOP/build/soong/soong_ui.bash" --make-mode androidmk
source "$(dirname "$0")/lib.sh"
@@ -113,11 +113,14 @@
run_androidmk_test "a/b/c/d/Android.mk" "a/b/c/d/Android.bp"
}
-run_androidmk_test () {
+function run_androidmk_test {
export ANDROID_BUILD_TOP="$MOCK_TOP"
-
- local out=$($REAL_TOP/*/host/*/bin/androidmk "$1")
- local expected=$(<"$2")
+ local -r androidmk=("$REAL_TOP"/*/host/*/bin/androidmk)
+ if [[ ${#androidmk[@]} -ne 1 ]]; then
+ fail "Multiple androidmk binaries found: ${androidmk[*]}"
+ fi
+ local -r out=$("${androidmk[0]}" "$1")
+ local -r expected=$(<"$2")
if [[ "$out" != "$expected" ]]; then
ANDROID_BUILD_TOP="$REAL_TOP"
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 78ddced..3cdf6aa 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -11,10 +11,10 @@
function test_bp2build_null_build() {
setup
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -36,10 +36,10 @@
touch foo/bar/a.txt foo/bar/b.txt
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -147,10 +147,10 @@
run_soong bp2build
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime1=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime1=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime2=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime2=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "output changed on null build"
@@ -161,7 +161,7 @@
EOF
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime3=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime3=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
if [[ "$output_mtime1" == "$output_mtime3" ]]; then
fail "output not changed when included header changed"
diff --git a/tests/lib.sh b/tests/lib.sh
index abe84d3..0c78cdf 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,7 +8,7 @@
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
-if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
MOCK_TOP="$HARDWIRED_MOCK_TOP"
else
MOCK_TOP=$(mktemp -t -d st.XXXXX)
@@ -36,37 +36,38 @@
}
function info {
- echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" $*
+ echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" "$*"
}
function fail {
- echo -e "\e[91;1mFAILED:\e[0m" $*
+ echo -e "\e[91;1mFAILED:\e[0m" "$*"
exit 1
}
-function copy_directory() {
+function copy_directory {
local dir="$1"
- local parent="$(dirname "$dir")"
+ local -r parent="$(dirname "$dir")"
mkdir -p "$MOCK_TOP/$parent"
cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
}
-function symlink_file() {
+function symlink_file {
local file="$1"
mkdir -p "$MOCK_TOP/$(dirname "$file")"
ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
}
-function symlink_directory() {
+function symlink_directory {
local dir="$1"
mkdir -p "$MOCK_TOP/$dir"
# We need to symlink the contents of the directory individually instead of
# using one symlink for the whole directory because finder.go doesn't follow
# symlinks when looking for Android.bp files
- for i in $(ls "$REAL_TOP/$dir"); do
+ for i in "$REAL_TOP/$dir"/*; do
+ i=$(basename "$i")
local target="$MOCK_TOP/$dir/$i"
local source="$REAL_TOP/$dir/$i"
@@ -96,7 +97,7 @@
touch "$MOCK_TOP/Android.bp"
}
-function setup() {
+function setup {
cleanup_mock_top
mkdir -p "$MOCK_TOP"
@@ -108,11 +109,12 @@
tar xzf "$WARMED_UP_MOCK_TOP"
}
-function run_soong() {
+# shellcheck disable=SC2120
+function run_soong {
build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
}
-function create_mock_bazel() {
+function create_mock_bazel {
copy_directory build/bazel
symlink_directory prebuilts/bazel
@@ -126,7 +128,7 @@
symlink_file tools/bazel
}
-run_bazel() {
+function run_bazel {
# Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its
# output should not be parsed as such.
rm -rf out/ninja_build
@@ -134,11 +136,11 @@
tools/bazel "$@"
}
-run_ninja() {
+function run_ninja {
build/soong/soong_ui.bash --make-mode --skip-config --soong-only --skip-soong-tests "$@"
}
-info "Starting Soong integration test suite $(basename $0)"
+info "Starting Soong integration test suite $(basename "$0")"
info "Mock top: $MOCK_TOP"
diff --git a/ui/terminal/simple_status.go b/ui/terminal/simple_status.go
index 3157813..cef3b5d 100644
--- a/ui/terminal/simple_status.go
+++ b/ui/terminal/simple_status.go
@@ -46,7 +46,11 @@
func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
if level >= s.outputLevel {
- fmt.Fprintln(s.writer, s.formatter.message(level, message))
+ output := s.formatter.message(level, message)
+ if !s.keepANSI {
+ output = string(stripAnsiEscapes([]byte(output)))
+ }
+ fmt.Fprintln(s.writer, output)
}
}
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 810e31d..b9057d2 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -81,9 +81,9 @@
},
{
name: "action with output with ansi codes",
- calls: actionWithOuptutWithAnsiCodes,
- smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
- simple: "[100% 1/1] action1\ncolor\n",
+ calls: actionWithOutputWithAnsiCodes,
+ smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n\x1b[31mcolor message\x1b[0m\n",
+ simple: "[100% 1/1] action1\ncolor\ncolor message\n",
},
}
@@ -257,12 +257,14 @@
runner.finishAction(result1)
}
-func actionWithOuptutWithAnsiCodes(stat status.StatusOutput) {
+func actionWithOutputWithAnsiCodes(stat status.StatusOutput) {
result1WithOutputWithAnsiCodes := status.ActionResult{Action: action1, Output: "\x1b[31mcolor\x1b[0m"}
runner := newRunner(stat, 1)
runner.startAction(action1)
runner.finishAction(result1WithOutputWithAnsiCodes)
+
+ stat.Message(status.PrintLvl, "\x1b[31mcolor message\x1b[0m")
}
func TestSmartStatusOutputWidthChange(t *testing.T) {