Merge changes from topic "uses-libs-5"
* changes:
Rewrite construct_context.sh in Python.
Refactor class loader context generation.
diff --git a/Android.bp b/Android.bp
index 0b44198..3075d67 100644
--- a/Android.bp
+++ b/Android.bp
@@ -106,15 +106,24 @@
},
arm64: {
src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86_64: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
},
}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 928ca03..ff85661 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,3 @@
[Builtin Hooks]
gofmt = true
+bpfmt = true
diff --git a/android/androidmk.go b/android/androidmk.go
index 3487b28..045cb59 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -58,7 +58,7 @@
Extra []AndroidMkExtraFunc
- preamble bytes.Buffer
+ Entries AndroidMkEntries
}
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
@@ -483,7 +483,7 @@
func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) {
// Get the preamble content through AndroidMkEntries logic.
- entries := AndroidMkEntries{
+ data.Entries = AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
DistFiles: data.DistFiles,
@@ -494,16 +494,12 @@
Host_required: data.Host_required,
Target_required: data.Target_required,
}
- entries.fillInEntries(config, bpPath, mod)
-
- // preamble doesn't need the footer content.
- entries.footer = bytes.Buffer{}
- entries.write(&data.preamble)
+ data.Entries.fillInEntries(config, bpPath, mod)
// copy entries back to data since it is used in Custom
- data.Required = entries.Required
- data.Host_required = entries.Host_required
- data.Target_required = entries.Target_required
+ data.Required = data.Entries.Required
+ data.Host_required = data.Entries.Host_required
+ data.Target_required = data.Entries.Target_required
}
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
@@ -559,7 +555,9 @@
return
}
- w.Write(data.preamble.Bytes())
+ // write preamble via Entries
+ data.Entries.footer = bytes.Buffer{}
+ data.Entries.write(w)
for _, extra := range data.Extra {
extra(w, data.OutputFile.Path())
diff --git a/android/config.go b/android/config.go
index 16f3d73..6f73a12 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1052,7 +1052,7 @@
// represents any path.
func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool {
coverage := false
- if c.config.productVariables.JavaCoveragePaths == nil ||
+ if len(c.config.productVariables.JavaCoveragePaths) == 0 ||
InList("*", c.config.productVariables.JavaCoveragePaths) ||
HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
coverage = true
diff --git a/android/neverallow.go b/android/neverallow.go
index 26e42e6..526d399 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -145,11 +145,18 @@
"prebuilts",
}
- // Core library constraints. The sdk_version: "none" can only be used in core library projects.
+ // Additional whitelisted path only used for ART testing, which needs access to core library
+ // targets. This does not affect the contents of a device image (system, vendor, etc.).
+ var artTests = []string{
+ "art/test",
+ }
+
+ // Core library constraints. The sdk_version: "none" can only be used in core library projects and ART tests.
// Access to core library targets is restricted using visibility rules.
rules := []Rule{
NeverAllow().
NotIn(coreLibraryProjects...).
+ NotIn(artTests...).
With("sdk_version", "none").
WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
}
diff --git a/android/override_module.go b/android/override_module.go
index 6b246db..3994084 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -28,6 +28,7 @@
// module based on it.
import (
+ "sort"
"sync"
"github.com/google/blueprint"
@@ -161,6 +162,11 @@
// Should NOT be used in the same mutator as addOverride.
func (b *OverridableModuleBase) getOverrides() []OverrideModule {
+ b.overridesLock.Lock()
+ sort.Slice(b.overrides, func(i, j int) bool {
+ return b.overrides[i].Name() < b.overrides[j].Name()
+ })
+ b.overridesLock.Unlock()
return b.overrides
}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 726746b..2448acc 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -876,7 +876,7 @@
prebuilt_etc {
name: "etc.test1",
src: "mymod",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -896,7 +896,7 @@
name: "etc.test1",
src: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -913,7 +913,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
device_specific: true,
}
@@ -931,7 +931,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
@@ -950,7 +950,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
}
@@ -968,7 +968,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
}
@@ -986,7 +986,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
@@ -1005,7 +1005,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1023,7 +1023,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1041,7 +1041,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1059,7 +1059,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
recovery: true,
}
@@ -1098,7 +1098,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1174,7 +1174,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1193,7 +1193,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1212,7 +1212,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1231,7 +1231,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
@@ -1251,7 +1251,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4dd14d8..7595238 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -33,14 +33,7 @@
Disabled: true,
}
}
- writers := []android.AndroidMkData{}
- writers = append(writers, a.androidMkForType())
- return android.AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- for _, data := range writers {
- data.Custom(w, name, prefix, moduleDir, data)
- }
- }}
+ return a.androidMkForType()
}
func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
@@ -308,6 +301,20 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+
+ // Because apex writes .mk with Custom(), we need to write manually some common properties
+ // which are available via data.Entries
+ commonProperties := []string{
+ "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
+ "LOCAL_MODULE_OWNER",
+ }
+ for _, name := range commonProperties {
+ if value, ok := data.Entries.EntryMap[name]; ok {
+ fmt.Fprintln(w, name+" := "+strings.Join(value, " "))
+ }
+ }
+
if len(a.overridableProperties.Overrides) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
}
diff --git a/apex/apex.go b/apex/apex.go
index a9be1a8..d0c1a09 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1329,6 +1329,7 @@
targets := ctx.MultiTargets()
config := ctx.DeviceConfig()
+ imageVariation := a.getImageVariation(ctx)
a.combineProperties(ctx)
@@ -1348,13 +1349,13 @@
Jni_libs: a.properties.Jni_libs,
Binaries: nil,
},
- target, a.getImageVariation(config))
+ target, imageVariation)
// Add native modules targetting both ABIs
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Both,
target,
- a.getImageVariation(config))
+ imageVariation)
isPrimaryAbi := i == 0
if isPrimaryAbi {
@@ -1367,13 +1368,13 @@
Jni_libs: nil,
Binaries: a.properties.Binaries,
},
- target, a.getImageVariation(config))
+ target, imageVariation)
// Add native modules targetting the first ABI
addDependenciesForNativeModules(ctx,
a.properties.Multilib.First,
target,
- a.getImageVariation(config))
+ imageVariation)
}
switch target.Arch.ArchType.Multilib {
@@ -1382,24 +1383,24 @@
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Lib32,
target,
- a.getImageVariation(config))
+ imageVariation)
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
+ imageVariation)
case "lib64":
// Add native modules targetting 64-bit ABI
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Lib64,
target,
- a.getImageVariation(config))
+ imageVariation)
if !has32BitTarget {
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
+ imageVariation)
}
}
}
@@ -1501,15 +1502,33 @@
return proptools.Bool(a.properties.Test_only_unsigned_payload)
}
-func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
+func (a *apexBundle) getImageVariation(ctx android.BottomUpMutatorContext) string {
+ deviceConfig := ctx.DeviceConfig()
if a.vndkApex {
- return cc.VendorVariationPrefix + a.vndkVersion(config)
+ return cc.VendorVariationPrefix + a.vndkVersion(deviceConfig)
}
- if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
- return cc.VendorVariationPrefix + config.PlatformVndkVersion()
- } else {
- return android.CoreVariation
+
+ var prefix string
+ var vndkVersion string
+ if deviceConfig.VndkVersion() != "" {
+ if proptools.Bool(a.properties.Use_vendor) {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ } else if a.SocSpecific() || a.DeviceSpecific() {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.VndkVersion()
+ } else if a.ProductSpecific() {
+ prefix = cc.ProductVariationPrefix
+ vndkVersion = deviceConfig.ProductVndkVersion()
+ }
}
+ if vndkVersion == "current" {
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ }
+ if vndkVersion != "" {
+ return prefix + vndkVersion
+ }
+ return android.CoreVariation
}
func (a *apexBundle) EnableSanitizer(sanitizerName string) {
@@ -1541,7 +1560,7 @@
for _, target := range ctx.MultiTargets() {
if target.Arch.ArchType.Multilib == "lib64" {
ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(ctx.DeviceConfig())},
+ {Mutator: "image", Variation: a.getImageVariation(ctx)},
{Mutator: "link", Variation: "shared"},
{Mutator: "version", Variation: ""}, // "" is the non-stub variant
}...), sharedLibTag, "libclang_rt.hwasan-aarch64-android")
@@ -1785,6 +1804,12 @@
return
}
+ // Because APEXes targeting other than system/system_ext partitions
+ // can't set apex_available, we skip checks for these APEXes
+ if ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific() {
+ return
+ }
+
// Coverage build adds additional dependencies for the coverage-only runtime libraries.
// Requiring them and their transitive depencies with apex_available is not right
// because they just add noise.
@@ -2099,7 +2124,7 @@
}
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
af.transitiveDep = true
- if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), ctx.OtherModuleName(cc)) && (cc.IsStubs() || cc.HasStubsVariants()) {
+ if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
// If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
@@ -2107,8 +2132,17 @@
//
// Always include if we are a host-apex however since those won't have any
// system libraries.
- if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.BaseModuleName(), a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, cc.BaseModuleName())
+ if !android.DirectlyInAnyApex(ctx, depName) {
+ // we need a module name for Make
+ name := cc.BaseModuleName() + cc.Properties.SubName
+ if proptools.Bool(a.properties.Use_vendor) {
+ // we don't use subName(.vendor) for a "use_vendor: true" apex
+ // which is supposed to be installed in /system
+ name = cc.BaseModuleName()
+ }
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
}
requireNativeLibs = append(requireNativeLibs, af.Stem())
// Don't track further
@@ -2203,6 +2237,12 @@
a.installable() &&
!proptools.Bool(a.properties.Use_vendor)
+ // APEXes targeting other than system/system_ext partitions use vendor/product variants.
+ // So we can't link them to /system/lib libs which are core variants.
+ if a.SocSpecific() || a.DeviceSpecific() || a.ProductSpecific() {
+ a.linkToSystemLib = false
+ }
+
// We don't need the optimization for updatable APEXes, as it might give false signal
// to the system health when the APEXes are still bundled (b/149805758)
if a.Updatable() && a.properties.ApexType == imageApex {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f1638c3..befb814 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2105,7 +2105,7 @@
ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so")
}
-func TestUseVendorRestriction(t *testing.T) {
+func TestUseVendorNotAllowedForSystemApexes(t *testing.T) {
testApexError(t, `module "myapex" .*: use_vendor: not allowed`, `
apex {
name: "myapex",
@@ -2161,6 +2161,141 @@
`)
}
+func TestVendorApex(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["mybin"],
+ vendor: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ vendor: true,
+ shared_libs: ["libfoo"],
+ }
+ cc_library {
+ name: "libfoo",
+ proprietary: true,
+ }
+ `)
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/mybin",
+ "lib64/libfoo.so",
+ // TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
+ "lib64/libc++.so",
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
+}
+
+func TestAndroidMk_UseVendorRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ use_vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ apex_available: ["myapex"],
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ setUseVendorAllowListForTest(config, []string{"myapex"})
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc libm libdl\n")
+}
+
+func TestAndroidMk_VendorApexRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc.vendor libm.vendor libdl.vendor\n")
+}
+
+func TestAndroidMkWritesCommonProperties(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vintf_fragments: ["fragment.xml"],
+ init_rc: ["init.rc"],
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
+ ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+}
+
func TestStaticLinking(t *testing.T) {
ctx, _ := testApex(t, `
apex {
diff --git a/apex/builder.go b/apex/builder.go
index ede11d0..5fb9a5f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -255,10 +255,15 @@
output := android.PathForModuleOut(ctx, "file_contexts")
rule := android.NewRuleBuilder()
+ // remove old file
rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ // copy file_contexts
rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+ // new line
rule.Command().Text("echo").Text(">>").Output(output)
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
a.fileContexts = output.OutputPath
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index e291578..b244e3a 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -44,11 +44,9 @@
"bpfix/bpfix.go",
],
testSrcs: [
- "bpfix/bpfix_test.go",
+ "bpfix/bpfix_test.go",
],
deps: [
"blueprint-parser",
],
}
-
-
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index e731750..689cbd1 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -533,7 +533,7 @@
updated = true
} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
m.Properties = append(m.Properties, &parser.Property{
- Name: "sub_dir",
+ Name: "relative_install_path",
Value: &parser.String{Value: trimmedPath},
})
updated = true
@@ -581,6 +581,8 @@
// 'srcs' --> 'src' conversion
convertToSingleSource(mod, "src")
+ renameProperty(mod, "sub_dir", "relative_install_dir")
+
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
// filename: and boolean attributes combination
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 64a7b93..8988177 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -742,6 +742,22 @@
}
`,
},
+ {
+ name: "prebuilt_etc sub_dir",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ sub_dir: "baz",
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ relative_install_dir: "baz",
+ }
+ `,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
diff --git a/cc/cc.go b/cc/cc.go
index c3b0d88..0a23967 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -873,7 +873,7 @@
}
func (c *Module) IsNdk() bool {
- return inList(c.Name(), ndkMigratedLibs)
+ return inList(c.Name(), ndkKnownLibs)
}
func (c *Module) isLlndk(config android.Config) bool {
@@ -1759,8 +1759,6 @@
variantNdkLibs := []string{}
variantLateNdkLibs := []string{}
if ctx.Os() == android.Android {
- version := ctx.sdkVersion()
-
// rewriteLibs takes a list of names of shared libraries and scans it for three types
// of names:
//
@@ -1802,12 +1800,8 @@
for _, entry := range list {
// strip #version suffix out
name, _ := StubsLibNameAndVersion(entry)
- if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
- if !inList(name, ndkMigratedLibs) {
- nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
- } else {
- variantLibs = append(variantLibs, name+ndkLibrarySuffix)
- }
+ if ctx.useSdk() && inList(name, ndkKnownLibs) {
+ variantLibs = append(variantLibs, name+ndkLibrarySuffix)
} else if ctx.useVndk() {
nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry))
} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
@@ -2988,6 +2982,7 @@
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
+ &BenchmarkProperties{},
&FuzzProperties{},
&StlProperties{},
&SanitizeProperties{},
diff --git a/cc/makevars.go b/cc/makevars.go
index 0f9f4c1..968eeb5 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -97,7 +97,6 @@
ctx.Strict("CLANG_EXTERNAL_CFLAGS", "${config.ClangExternalCflags}")
ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.NoOverrideClangGlobalCflags}")
ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
- ctx.Strict("NDK_PREBUILT_SHARED_LIBRARIES", strings.Join(ndkPrebuiltSharedLibs, " "))
ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
@@ -174,8 +173,8 @@
ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " "))
ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " "))
- sort.Strings(ndkMigratedLibs)
- ctx.Strict("NDK_MIGRATED_LIBS", strings.Join(ndkMigratedLibs, " "))
+ sort.Strings(ndkKnownLibs)
+ ctx.Strict("NDK_KNOWN_LIBS", strings.Join(ndkKnownLibs, " "))
hostTargets := ctx.Config().Targets[android.BuildOs]
makeVarsToolchain(ctx, "", hostTargets[0])
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 5ef9a78..6299b00 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -47,37 +47,10 @@
ndkLibrarySuffix = ".ndk"
- ndkPrebuiltSharedLibs = []string{
- "aaudio",
- "amidi",
- "android",
- "binder_ndk",
- "c",
- "camera2ndk",
- "dl",
- "EGL",
- "GLESv1_CM",
- "GLESv2",
- "GLESv3",
- "jnigraphics",
- "log",
- "mediandk",
- "nativewindow",
- "m",
- "neuralnetworks",
- "OpenMAXAL",
- "OpenSLES",
- "stdc++",
- "sync",
- "vulkan",
- "z",
- }
- ndkPrebuiltSharedLibraries = addPrefix(append([]string(nil), ndkPrebuiltSharedLibs...), "lib")
-
- // These libraries have migrated over to the new ndk_library, which is added
- // as a variation dependency via depsMutator.
- ndkMigratedLibs = []string{}
- ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel BeginMutator
+ // Added as a variation dependency via depsMutator.
+ ndkKnownLibs = []string{}
+ // protects ndkKnownLibs writes during parallel BeginMutator.
+ ndkKnownLibsLock sync.Mutex
)
// Creates a stub shared library based on the provided version file.
@@ -257,14 +230,14 @@
ctx.PropertyErrorf("name", "Do not append %q manually, just use the base name", ndkLibrarySuffix)
}
- ndkMigratedLibsLock.Lock()
- defer ndkMigratedLibsLock.Unlock()
- for _, lib := range ndkMigratedLibs {
+ ndkKnownLibsLock.Lock()
+ defer ndkKnownLibsLock.Unlock()
+ for _, lib := range ndkKnownLibs {
if lib == name {
return
}
}
- ndkMigratedLibs = append(ndkMigratedLibs, name)
+ ndkKnownLibs = append(ndkKnownLibs, name)
}
func addStubLibraryCompilerFlags(flags Flags) Flags {
diff --git a/cc/pgo.go b/cc/pgo.go
index 88903bb..9298e7a 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -34,7 +34,7 @@
globalPgoProfileProjects = []string{
"toolchain/pgo-profiles",
- "vendor/google_data/pgo-profiles",
+ "vendor/google_data/pgo_profile",
}
)
diff --git a/cc/testing.go b/cc/testing.go
index b5cf45c..b0c3c162 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -32,6 +32,7 @@
ctx.RegisterModuleType("cc_object", ObjectFactory)
ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
+ ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
}
func GatherRequiredDepsForTest(oses ...android.OsType) string {
@@ -393,25 +394,22 @@
system_shared_libs: [],
}
- cc_library {
- name: "libc.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
+ ndk_library {
+ name: "libc",
+ first_version: "minimum",
+ symbol_file: "libc.map.txt",
}
- cc_library {
- name: "libm.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
+ ndk_library {
+ name: "libm",
+ first_version: "minimum",
+ symbol_file: "libm.map.txt",
}
- cc_library {
- name: "libdl.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
+ ndk_library {
+ name: "libdl",
+ first_version: "minimum",
+ symbol_file: "libdl.map.txt",
}
ndk_prebuilt_object {
@@ -503,7 +501,6 @@
ctx.RegisterModuleType("cc_fuzz", FuzzFactory)
ctx.RegisterModuleType("cc_test", TestFactory)
ctx.RegisterModuleType("llndk_headers", llndkHeadersFactory)
- ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
ctx.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 4dad730..fec0c8b 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -569,7 +569,13 @@
return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
}
if l.shared() {
- return m.outputFile.Valid() && !m.IsVndk()
+ if !m.outputFile.Valid() {
+ return false
+ }
+ if !m.IsVndk() {
+ return true
+ }
+ return m.isVndkExt()
}
return true
}
@@ -669,7 +675,16 @@
// Common properties among snapshots.
prop.ModuleName = ctx.ModuleName(m)
- prop.RelativeInstallPath = m.RelativeInstallPath()
+ if m.isVndkExt() {
+ // vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
+ if m.isVndkSp() {
+ prop.RelativeInstallPath = "vndk-sp"
+ } else {
+ prop.RelativeInstallPath = "vndk"
+ }
+ } else {
+ prop.RelativeInstallPath = m.RelativeInstallPath()
+ }
prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
prop.Required = m.RequiredModuleNames()
for _, path := range m.InitRc() {
diff --git a/cmd/extract_apks/Android.bp b/cmd/extract_apks/Android.bp
index 90548cd..f8fe864 100644
--- a/cmd/extract_apks/Android.bp
+++ b/cmd/extract_apks/Android.bp
@@ -6,7 +6,7 @@
"golang-protobuf-proto",
"soong-cmd-extract_apks-proto",
],
- testSrcs: ["main_test.go"]
+ testSrcs: ["main_test.go"],
}
bootstrap_go_package {
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index e9a850e..db54ffb 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -24,6 +24,7 @@
"math"
"os"
"regexp"
+ "sort"
"strings"
"github.com/golang/protobuf/proto"
@@ -355,7 +356,7 @@
// Writes out selected entries, renaming them as needed
func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
- writer Zip2ZipWriter) error {
+ writer Zip2ZipWriter, partition string) ([]string, error) {
// Renaming rules:
// splits/MODULE-master.apk to STEM.apk
// else
@@ -389,10 +390,11 @@
}
entryOrigin := make(map[string]string) // output entry to input entry
+ var apkcerts []string
for _, apk := range selected.entries {
apkFile, ok := apkSet.entries[apk]
if !ok {
- return fmt.Errorf("TOC refers to an entry %s which does not exist", apk)
+ return nil, fmt.Errorf("TOC refers to an entry %s which does not exist", apk)
}
inName := apkFile.Name
outName, ok := renamer(inName)
@@ -405,10 +407,15 @@
}
entryOrigin[outName] = inName
if err := writer.CopyFrom(apkFile, outName); err != nil {
- return err
+ return nil, err
+ }
+ if partition != "" {
+ apkcerts = append(apkcerts, fmt.Sprintf(
+ `name="%s" certificate="PRESIGNED" private_key="" partition="%s"`, outName, partition))
}
}
- return nil
+ sort.Strings(apkcerts)
+ return apkcerts, nil
}
func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os.File) error {
@@ -433,6 +440,9 @@
}
extractSingle = flag.Bool("extract-single", false,
"extract a single target and output it uncompressed. only available for standalone apks and apexes.")
+ apkcertsOutput = flag.String("apkcerts", "",
+ "optional apkcerts.txt output file containing signing info of all outputted apks")
+ partition = flag.String("partition", "", "partition string. required when -apkcerts is used.")
)
// Parse abi values
@@ -485,7 +495,8 @@
func processArgs() {
flag.Usage = func() {
fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
- `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] <APK set>`)
+ `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
+ `[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
flag.PrintDefaults()
os.Exit(2)
}
@@ -498,7 +509,8 @@
"allow prereleased")
flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
- if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || (targetConfig.stem == "" && !*extractSingle) {
+ if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
+ (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") {
flag.Usage()
}
targetConfig.sdkVersion = int32(*version)
@@ -536,7 +548,20 @@
log.Fatal(err)
}
}()
- err = apkSet.writeApks(sel, targetConfig, writer)
+ apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)
+ if err == nil && *apkcertsOutput != "" {
+ apkcertsFile, err := os.Create(*apkcertsOutput)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer apkcertsFile.Close()
+ for _, a := range apkcerts {
+ _, err = apkcertsFile.WriteString(a + "\n")
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ }
}
if err != nil {
log.Fatal(err)
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index bdd4bec..c3e6a2d 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -16,10 +16,11 @@
import (
"fmt"
- "github.com/golang/protobuf/proto"
"reflect"
"testing"
+ "github.com/golang/protobuf/proto"
+
bp "android/soong/cmd/extract_apks/bundle_proto"
"android/soong/third_party/zip"
)
@@ -430,48 +431,63 @@
return nil
}
-type testCaseWriteZip struct {
+type testCaseWriteApks struct {
name string
moduleName string
stem string
+ partition string
// what we write from what
- expected map[string]string
+ expectedZipEntries map[string]string
+ expectedApkcerts []string
}
-func TestWriteZip(t *testing.T) {
- testCases := []testCaseWriteZip{
+func TestWriteApks(t *testing.T) {
+ testCases := []testCaseWriteApks{
{
name: "splits",
moduleName: "mybase",
stem: "Foo",
- expected: map[string]string{
+ partition: "system",
+ expectedZipEntries: map[string]string{
"Foo.apk": "splits/mybase-master.apk",
"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
},
+ expectedApkcerts: []string{
+ `name="Foo-xhdpi.apk" certificate="PRESIGNED" private_key="" partition="system"`,
+ `name="Foo.apk" certificate="PRESIGNED" private_key="" partition="system"`,
+ },
},
{
name: "universal",
moduleName: "base",
stem: "Bar",
- expected: map[string]string{
+ partition: "product",
+ expectedZipEntries: map[string]string{
"Bar.apk": "universal.apk",
},
+ expectedApkcerts: []string{
+ `name="Bar.apk" certificate="PRESIGNED" private_key="" partition="product"`,
+ },
},
}
for _, testCase := range testCases {
apkSet := ApkSet{entries: make(map[string]*zip.File)}
sel := SelectionResult{moduleName: testCase.moduleName}
- for _, in := range testCase.expected {
+ for _, in := range testCase.expectedZipEntries {
apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
sel.entries = append(sel.entries, in)
}
writer := testZip2ZipWriter{make(map[string]string)}
config := TargetConfig{stem: testCase.stem}
- if err := apkSet.writeApks(sel, config, writer); err != nil {
+ apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition)
+ if err != nil {
t.Error(err)
}
- if !reflect.DeepEqual(testCase.expected, writer.entries) {
- t.Errorf("expected %v, got %v", testCase.expected, writer.entries)
+ if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) {
+ t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries)
+ }
+ if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
+ t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
}
}
}
diff --git a/cmd/extract_jar_packages/Android.bp b/cmd/extract_jar_packages/Android.bp
index ea0cbbf..4ea8798 100644
--- a/cmd/extract_jar_packages/Android.bp
+++ b/cmd/extract_jar_packages/Android.bp
@@ -22,4 +22,3 @@
"extract_jar_packages.go",
],
}
-
diff --git a/cmd/extract_linker/Android.bp b/cmd/extract_linker/Android.bp
index fe76ae4..690c4fa 100644
--- a/cmd/extract_linker/Android.bp
+++ b/cmd/extract_linker/Android.bp
@@ -17,4 +17,3 @@
srcs: ["main.go"],
testSrcs: ["main_test.go"],
}
-
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
index f70c86e..8c97b6d 100644
--- a/cmd/merge_zips/Android.bp
+++ b/cmd/merge_zips/Android.bp
@@ -15,10 +15,10 @@
blueprint_go_binary {
name: "merge_zips",
deps: [
- "android-archive-zip",
- "blueprint-pathtools",
- "soong-jar",
- "soong-zip",
+ "android-archive-zip",
+ "blueprint-pathtools",
+ "soong-jar",
+ "soong-zip",
],
srcs: [
"merge_zips.go",
@@ -27,4 +27,3 @@
"merge_zips_test.go",
],
}
-
diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp
index a706810d..6fa304e 100644
--- a/cmd/sbox/Android.bp
+++ b/cmd/sbox/Android.bp
@@ -19,4 +19,3 @@
"sbox.go",
],
}
-
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 6b79823..b559bac 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -29,4 +29,3 @@
],
primaryBuilder: true,
}
-
diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp
index 4cdc396..4db0da3 100644
--- a/cmd/soong_env/Android.bp
+++ b/cmd/soong_env/Android.bp
@@ -22,4 +22,3 @@
],
default: true,
}
-
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 68d8bc7..2c4cd82 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -24,4 +24,3 @@
],
testSrcs: ["zip2zip_test.go"],
}
-
diff --git a/cmd/zipsync/Android.bp b/cmd/zipsync/Android.bp
index 22feadc..49b5f3e 100644
--- a/cmd/zipsync/Android.bp
+++ b/cmd/zipsync/Android.bp
@@ -22,4 +22,3 @@
"zipsync.go",
],
}
-
diff --git a/dexpreopt/dexpreopt_gen/Android.bp b/dexpreopt/dexpreopt_gen/Android.bp
index 0790391..3f0619c 100644
--- a/dexpreopt/dexpreopt_gen/Android.bp
+++ b/dexpreopt/dexpreopt_gen/Android.bp
@@ -8,4 +8,4 @@
"blueprint-pathtools",
"blueprint-proptools",
],
-}
\ No newline at end of file
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index df6d79d..0f7b8df 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -42,9 +42,12 @@
// Source file of this prebuilt.
Src *string `android:"path,arch_variant"`
- // optional subdirectory under which this file is installed into
+ // optional subdirectory under which this file is installed into, cannot be specified with relative_install_path, prefer relative_install_path
Sub_dir *string `android:"arch_variant"`
+ // optional subdirectory under which this file is installed into, cannot be specified with sub_dir
+ Relative_install_path *string `android:"arch_variant"`
+
// optional name for the installed file. If unspecified, name of the module is used as the file name
Filename *string `android:"arch_variant"`
@@ -158,7 +161,10 @@
}
func (p *PrebuiltEtc) SubDir() string {
- return android.String(p.properties.Sub_dir)
+ if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
+ return subDir
+ }
+ return proptools.String(p.properties.Relative_install_path)
}
func (p *PrebuiltEtc) Installable() bool {
@@ -181,13 +187,17 @@
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+ if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
+ ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+ }
+
// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
// socInstallDirBase.
installBaseDir := p.installDirBase
if ctx.SocSpecific() && p.socInstallDirBase != "" {
installBaseDir = p.socInstallDirBase
}
- p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, proptools.String(p.properties.Sub_dir))
+ p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 4ce1984..8fc36c2 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -49,7 +49,7 @@
os.Exit(run())
}
-func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+func testPrebuiltEtcContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
fs := map[string][]byte{
"foo.conf": nil,
"bar.conf": nil,
@@ -67,6 +67,14 @@
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.Register(config)
+
+ return ctx, config
+}
+
+func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -75,6 +83,24 @@
return ctx, config
}
+func testPrebuiltEtcError(t *testing.T, pattern, bp string) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
func TestPrebuiltEtcVariants(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc {
@@ -184,6 +210,33 @@
}
}
+func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ relative_install_path: "bar",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+ expected := buildDir + "/target/product/test_device/system/etc/bar"
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
+ }
+}
+
+func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
+ testPrebuiltEtcError(t, "relative_install_path is set. Cannot set sub_dir", `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ sub_dir: "bar",
+ relative_install_path: "bar",
+ }
+ `)
+}
+
func TestPrebuiltEtcHost(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc_host {
diff --git a/finder/Android.bp b/finder/Android.bp
index 47b47c9..a5d7fd4 100644
--- a/finder/Android.bp
+++ b/finder/Android.bp
@@ -17,7 +17,7 @@
//
subdirs = [
- "cmd"
+ "cmd",
]
bootstrap_go_package {
@@ -30,8 +30,6 @@
"finder_test.go",
],
deps: [
- "soong-finder-fs",
+ "soong-finder-fs",
],
}
-
-
diff --git a/finder/cmd/Android.bp b/finder/cmd/Android.bp
index 9dc84ae..e066c39 100644
--- a/finder/cmd/Android.bp
+++ b/finder/cmd/Android.bp
@@ -22,8 +22,6 @@
"finder.go",
],
deps: [
- "soong-finder"
+ "soong-finder",
],
}
-
-
diff --git a/finder/finder.go b/finder/finder.go
index 89be0f5..f20bed2 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -1393,17 +1393,25 @@
for _, child := range children {
linkBits := child.Mode() & os.ModeSymlink
isLink := linkBits != 0
- if child.IsDir() {
- if !isLink {
+ if isLink {
+ childPath := filepath.Join(path, child.Name())
+ childStat, err := f.filesystem.Stat(childPath)
+ if err != nil {
+ // If stat fails this is probably a broken or dangling symlink, treat it as a file.
+ subfiles = append(subfiles, child.Name())
+ } else if childStat.IsDir() {
// Skip symlink dirs.
// We don't have to support symlink dirs because
// that would cause duplicates.
- subdirs = append(subdirs, child.Name())
+ } else {
+ // We do have to support symlink files because the link name might be
+ // different than the target name
+ // (for example, Android.bp -> build/soong/root.bp)
+ subfiles = append(subfiles, child.Name())
}
+ } else if child.IsDir() {
+ subdirs = append(subdirs, child.Name())
} else {
- // We do have to support symlink files because the link name might be
- // different than the target name
- // (for example, Android.bp -> build/soong/root.bp)
subfiles = append(subfiles, child.Name())
}
diff --git a/finder/finder_test.go b/finder/finder_test.go
index f6d0aa9..88b0c05 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -20,11 +20,8 @@
"log"
"os"
"path/filepath"
- "reflect"
- "runtime/debug"
"sort"
"testing"
- "time"
"android/soong/finder/fs"
)
@@ -41,7 +38,7 @@
func newFinderWithNumThreads(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) *Finder {
f, err := newFinderAndErr(t, filesystem, cacheParams, numThreads)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -62,7 +59,7 @@
func finderWithSameParams(t *testing.T, original *Finder) *Finder {
f, err := finderAndErrorWithSameParams(t, original)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -78,146 +75,13 @@
return f, err
}
-func write(t *testing.T, path string, content string, filesystem *fs.MockFs) {
- parent := filepath.Dir(path)
- filesystem.MkDirs(parent)
- err := filesystem.WriteFile(path, []byte(content), 0777)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func create(t *testing.T, path string, filesystem *fs.MockFs) {
- write(t, path, "hi", filesystem)
-}
-
-func delete(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.Remove(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func removeAll(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.RemoveAll(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func move(t *testing.T, oldPath string, newPath string, filesystem *fs.MockFs) {
- err := filesystem.Rename(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func link(t *testing.T, newPath string, oldPath string, filesystem *fs.MockFs) {
- parentPath := filepath.Dir(newPath)
- err := filesystem.MkDirs(parentPath)
- if err != nil {
- t.Fatal(err.Error())
- }
- err = filesystem.Symlink(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-func read(t *testing.T, path string, filesystem *fs.MockFs) string {
- reader, err := filesystem.Open(path)
- if err != nil {
- t.Fatalf(err.Error())
- }
- bytes, err := ioutil.ReadAll(reader)
- if err != nil {
- t.Fatal(err.Error())
- }
- return string(bytes)
-}
-func modTime(t *testing.T, path string, filesystem *fs.MockFs) time.Time {
- stats, err := filesystem.Lstat(path)
- if err != nil {
- t.Fatal(err.Error())
- }
- return stats.ModTime()
-}
-func setReadable(t *testing.T, path string, readable bool, filesystem *fs.MockFs) {
- err := filesystem.SetReadable(path, readable)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func setReadErr(t *testing.T, path string, readErr error, filesystem *fs.MockFs) {
- err := filesystem.SetReadErr(path, readErr)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func fatal(t *testing.T, message string) {
- t.Error(message)
- debug.PrintStack()
- t.FailNow()
-}
-
-func assertSameResponse(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
- len(expected), expected, len(actual), actual),
- )
- }
-}
-
-func assertSameStatCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect Stat calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-func assertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect ReadDir calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-
// runSimpleTests creates a few files, searches for findme.txt, and checks for the expected matches
func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []string) {
filesystem := newFs()
root := "/tmp"
filesystem.MkDirs(root)
for _, path := range existentPaths {
- create(t, filepath.Join(root, path), filesystem)
+ fs.Create(t, filepath.Join(root, path), filesystem)
}
finder := newFinder(t,
@@ -237,7 +101,7 @@
for i := range expectedMatches {
absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
}
- assertSameResponse(t, foundPaths, absoluteMatches)
+ fs.AssertSameResponse(t, foundPaths, absoluteMatches)
}
// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
@@ -288,7 +152,7 @@
func TestEmptyPath(t *testing.T) {
filesystem := newFs()
root := "/tmp"
- create(t, filepath.Join(root, "findme.txt"), filesystem)
+ fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
finder := newFinder(
t,
@@ -302,7 +166,7 @@
foundPaths := finder.FindNamedAt("", "findme.txt")
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
}
func TestFilesystemRoot(t *testing.T) {
@@ -311,7 +175,7 @@
filesystem := newFs()
root := "/"
createdPath := "/findme.txt"
- create(t, createdPath, filesystem)
+ fs.Create(t, createdPath, filesystem)
finder := newFinderWithNumThreads(
t,
@@ -326,7 +190,7 @@
foundPaths := finder.FindNamedAt(root, "findme.txt")
- assertSameResponse(t, foundPaths, []string{createdPath})
+ fs.AssertSameResponse(t, foundPaths, []string{createdPath})
}
testAgainstSeveralThreadcounts(t, testWithNumThreads)
@@ -334,7 +198,7 @@
func TestNonexistentDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
_, err := newFinderAndErr(
t,
@@ -346,18 +210,18 @@
1,
)
if err == nil {
- fatal(t, "Did not fail when given a nonexistent root directory")
+ t.Fatal("Did not fail when given a nonexistent root directory")
}
}
func TestExcludeDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/exclude/findme.txt", filesystem)
- create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
- create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
finder := newFinder(
t,
@@ -372,7 +236,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/subdir/findme.txt",
"/tmp/subdir/subdir/findme.txt"})
@@ -380,15 +244,15 @@
func TestPruneFiles(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/out/findme.txt", filesystem)
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
- create(t, "/tmp/out/child/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
- create(t, "/tmp/out2/.ignore-out-dir", filesystem)
- create(t, "/tmp/out2/sub/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/include/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/include/findme.txt", filesystem)
finder := newFinder(
t,
@@ -403,7 +267,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/include/findme.txt"})
}
@@ -412,10 +276,10 @@
// tests of the filesystem root are in TestFilesystemRoot
func TestRootDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -429,17 +293,17 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/a/subdir/findme.txt"})
}
func TestUncachedDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -456,7 +320,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -464,9 +328,9 @@
func TestSearchingForFilesExcludedFromCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it
finder := newFinder(
@@ -483,7 +347,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -491,12 +355,12 @@
func TestRelativeFilePaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/ignore/hi.txt", filesystem)
- create(t, "/tmp/include/hi.txt", filesystem)
- create(t, "/cwd/hi.txt", filesystem)
- create(t, "/cwd/a/hi.txt", filesystem)
- create(t, "/cwd/a/a/hi.txt", filesystem)
- create(t, "/rel/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
+ fs.Create(t, "/tmp/include/hi.txt", filesystem)
+ fs.Create(t, "/cwd/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
+ fs.Create(t, "/rel/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -509,25 +373,25 @@
defer finder.Shutdown()
foundPaths := finder.FindNamedAt("a", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
foundPaths = finder.FindNamedAt(".", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"hi.txt",
"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/rel", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/rel/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
}
// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
@@ -535,7 +399,7 @@
func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
finder := newFinder(
t,
@@ -549,15 +413,15 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
}
func TestFindFirst(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
- create(t, "/tmp/b/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -571,7 +435,7 @@
foundPaths := finder.FindFirstNamed("hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/hi.txt",
"/tmp/b/hi.txt"},
)
@@ -593,7 +457,7 @@
}
sort.Strings(paths)
for _, path := range paths {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -621,7 +485,7 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
foundPaths := <-results
- assertSameResponse(t, foundPaths, paths)
+ fs.AssertSameResponse(t, foundPaths, paths)
}
}
@@ -649,7 +513,7 @@
}
sort.Strings(allFiles)
for _, path := range allFiles {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -687,16 +551,16 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
testRun := <-testRuns
- assertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
+ fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
}
}
func TestStrangelyFormattedPaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
finder := newFinder(
t,
@@ -710,7 +574,7 @@
foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
"/tmp/findme.txt"})
@@ -719,9 +583,9 @@
func TestCorruptedCacheHeader(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- write(t, "/finder/finder-db", "sample header", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Write(t, "/finder/finder-db", "sample header", filesystem)
finder := newFinder(
t,
@@ -735,7 +599,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/findme.txt"})
}
@@ -743,8 +607,8 @@
func TestCanUseCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -759,11 +623,11 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
finder.Shutdown()
// check results
- cacheText := read(t, finder.DbPath, filesystem)
+ cacheText := fs.Read(t, finder.DbPath, filesystem)
if len(cacheText) < 1 {
t.Fatalf("saved cache db is empty\n")
}
@@ -780,8 +644,8 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
- assertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
finder2.Shutdown()
}
@@ -789,8 +653,8 @@
func TestCorruptedCacheBody(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -807,7 +671,7 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numStatCalls := len(filesystem.StatCalls)
numReadDirCalls := len(filesystem.ReadDirCalls)
@@ -828,7 +692,7 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numNewStatCalls := len(filesystem.StatCalls)
numNewReadDirCalls := len(filesystem.ReadDirCalls)
// It's permissable to make more Stat calls with a corrupted cache because
@@ -853,7 +717,7 @@
func TestStatCalls(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run finder
finder := newFinder(
@@ -868,19 +732,19 @@
finder.Shutdown()
// check response
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
}
func TestFileAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -895,11 +759,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -908,9 +772,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
finder2.Shutdown()
}
@@ -918,11 +782,11 @@
func TestDirectoriesAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -936,13 +800,13 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/new/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -950,11 +814,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt", "/tmp/b/c/new/findme.txt", "/tmp/b/c/new/new2/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
finder2.Shutdown()
}
@@ -962,8 +826,8 @@
func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi1.txt", filesystem)
- create(t, "/tmp/a/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi1.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -977,12 +841,12 @@
foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/hi2.txt", filesystem)
- create(t, "/tmp/a/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi2.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -990,11 +854,11 @@
foundPaths = finder2.FindAll()
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
finder2.Shutdown()
}
@@ -1002,11 +866,11 @@
func TestFileDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1020,11 +884,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- delete(t, "/tmp/b/findme.txt", filesystem)
+ fs.Delete(t, "/tmp/b/findme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1032,9 +896,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
finder2.Shutdown()
}
@@ -1042,11 +906,11 @@
func TestDirectoriesDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1060,7 +924,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1069,7 +933,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- removeAll(t, "/tmp/a/1", filesystem)
+ fs.RemoveAll(t, "/tmp/a/1", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1077,7 +941,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
// if the Finder detects the nonexistence of /tmp/a/1
@@ -1087,9 +951,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
finder2.Shutdown()
}
@@ -1097,11 +961,11 @@
func TestDirectoriesMoved(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1115,7 +979,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1124,7 +988,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/c", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1132,7 +996,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/b/findme.txt",
"/tmp/c/findme.txt",
@@ -1146,20 +1010,20 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
finder2.Shutdown()
}
func TestDirectoriesSwapped(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1173,7 +1037,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1182,9 +1046,9 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/temp", filesystem)
- move(t, "/tmp/b", "/tmp/a", filesystem)
- move(t, "/tmp/temp", "/tmp/b", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
+ fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
+ fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1192,7 +1056,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
@@ -1206,9 +1070,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
finder2.Shutdown()
}
@@ -1217,15 +1081,15 @@
// runFsReplacementTest is a helper method called by other tests
func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
// setup fs1
- create(t, "/tmp/findme.txt", fs1)
- create(t, "/tmp/a/findme.txt", fs1)
- create(t, "/tmp/a/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/a/findme.txt", fs1)
// setup fs2 to have the same directories but different files
- create(t, "/tmp/findme.txt", fs2)
- create(t, "/tmp/a/findme.txt", fs2)
- create(t, "/tmp/a/a/ignoreme.txt", fs2)
- create(t, "/tmp/a/b/findme.txt", fs2)
+ fs.Create(t, "/tmp/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
+ fs.Create(t, "/tmp/a/b/findme.txt", fs2)
// run the first finder
finder := newFinder(
@@ -1239,12 +1103,12 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
// copy the cache data from the first filesystem to the second
- cacheContent := read(t, finder.DbPath, fs1)
- write(t, finder.DbPath, cacheContent, fs2)
+ cacheContent := fs.Read(t, finder.DbPath, fs1)
+ fs.Write(t, finder.DbPath, cacheContent, fs2)
// run the second finder, with the same config and same cache contents but a different filesystem
finder2 := newFinder(
@@ -1258,11 +1122,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
- assertSameStatCalls(t, fs2.StatCalls,
+ fs.AssertSameStatCalls(t, fs2.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
- assertSameReadDirCalls(t, fs2.ReadDirCalls,
+ fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
finder2.Shutdown()
}
@@ -1292,7 +1156,7 @@
// setup filesystem
filesystem := newFs()
for i := 0; i < 5; i++ {
- create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
+ fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
}
// run the first finder
@@ -1308,7 +1172,7 @@
finder.Shutdown()
// read db file
- string1 := read(t, finder.DbPath, filesystem)
+ string1 := fs.Read(t, finder.DbPath, filesystem)
err := filesystem.Remove(finder.DbPath)
if err != nil {
@@ -1320,7 +1184,7 @@
finder2.FindNamedAt("/tmp", "findme.txt")
finder2.Shutdown()
- string2 := read(t, finder.DbPath, filesystem)
+ string2 := fs.Read(t, finder.DbPath, filesystem)
if string1 != string2 {
t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
@@ -1343,9 +1207,9 @@
func TestNumSyscallsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1357,15 +1221,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it doesn't check the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, refoundPaths, foundPaths)
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, foundPaths)
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1373,9 +1237,9 @@
func TestChangingParamsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/metoo.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/metoo.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1387,15 +1251,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it gets the right answer without asking the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
- assertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1403,15 +1267,15 @@
func TestSymlinkPointingToFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/ignoreme.txt", filesystem)
- link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
- link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
- link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
+ fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
+ fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1432,20 +1296,21 @@
"/tmp/d/hi.txt",
"/tmp/f/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
func TestSymlinkPointingToDirectory(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/dir/hi.txt", filesystem)
- create(t, "/tmp/dir/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/dir/hi.txt", filesystem)
+ fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
- link(t, "/tmp/links/dir", "../dir", filesystem)
- link(t, "/tmp/links/link", "../dir", filesystem)
- link(t, "/tmp/links/broken", "nothingHere", filesystem)
- link(t, "/tmp/links/recursive", "recursive", filesystem)
+ fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/link", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1463,7 +1328,7 @@
correctResponse := []string{
"/tmp/dir/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
@@ -1472,9 +1337,9 @@
func TestAddPruneFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/out/hi.txt", filesystem)
- create(t, "/tmp/out/a/hi.txt", filesystem)
- create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
// do find
finder := newFinder(
@@ -1490,7 +1355,7 @@
foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
// check result
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi.txt",
"/tmp/out/hi.txt",
"/tmp/out/a/hi.txt"},
@@ -1499,19 +1364,19 @@
// modify filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
// run another find and check its result
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
finder2.Shutdown()
}
func TestUpdatingDbIffChanged(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/bye.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/bye.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1526,11 +1391,11 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -1539,10 +1404,10 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
expectedDbWriteTime := filesystem.Clock.Time()
- actualDbWriteTime := modTime(t, finder2.DbPath, filesystem)
+ actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
expectedDbWriteTime, actualDbWriteTime)
@@ -1556,10 +1421,10 @@
foundPaths = finder3.FindAll()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder3.Shutdown()
- actualDbWriteTime = modTime(t, finder3.DbPath, filesystem)
+ actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Re-wrote db even when contents did not change")
}
@@ -1569,10 +1434,10 @@
func TestDirectoryNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1588,12 +1453,12 @@
finder.Shutdown()
allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
// modify the filesystem
filesystem.Clock.Tick()
- setReadable(t, "/tmp/a", false, filesystem)
+ fs.SetReadable(t, "/tmp/a", false, filesystem)
filesystem.Clock.Tick()
// run the second finder
@@ -1601,24 +1466,24 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
// modify the filesystem back
- setReadable(t, "/tmp/a", true, filesystem)
+ fs.SetReadable(t, "/tmp/a", true, filesystem)
// run the third finder
finder3 := finderWithSameParams(t, finder2)
foundPaths = finder3.FindAll()
finder3.Shutdown()
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
}
func TestFileNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- setReadable(t, "/tmp/hi.txt", false, filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
// run the first finder
finder := newFinder(
@@ -1633,13 +1498,13 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
}
func TestCacheEntryPathUnexpectedError(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1654,14 +1519,14 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// make the directory not readable
- setReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
+ fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
// run the second finder
_, err := finderAndErrorWithSameParams(t, finder)
if err == nil {
- fatal(t, "Failed to detect unexpected filesystem error")
+ t.Fatal("Failed to detect unexpected filesystem error")
}
}
diff --git a/finder/fs/Android.bp b/finder/fs/Android.bp
index 27e3c7d..85929ae 100644
--- a/finder/fs/Android.bp
+++ b/finder/fs/Android.bp
@@ -22,8 +22,10 @@
srcs: [
"fs.go",
"readdir.go",
+ "test.go",
],
testSrcs: [
+ "fs_test.go",
"readdir_test.go",
],
darwin: {
@@ -37,4 +39,3 @@
],
},
}
-
diff --git a/finder/fs/fs.go b/finder/fs/fs.go
index 071f764..d2e3e4a 100644
--- a/finder/fs/fs.go
+++ b/finder/fs/fs.go
@@ -51,6 +51,7 @@
// getting information about files
Open(name string) (file io.ReadCloser, err error)
Lstat(path string) (stats os.FileInfo, err error)
+ Stat(path string) (stats os.FileInfo, err error)
ReadDir(path string) (contents []DirEntryInfo, err error)
InodeNumber(info os.FileInfo) (number uint64, err error)
@@ -99,6 +100,10 @@
return os.Lstat(path)
}
+func (osFs) Stat(path string) (stats os.FileInfo, err error) {
+ return os.Stat(path)
+}
+
func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
entries, err := readdir(path)
if err != nil {
@@ -376,7 +381,7 @@
size int64
modTime time.Time // time at which the inode's contents were modified
permTime time.Time // time at which the inode's permissions were modified
- isDir bool
+ mode os.FileMode
inodeNumber uint64
deviceNumber uint64
}
@@ -390,7 +395,7 @@
}
func (m *mockFileInfo) Mode() os.FileMode {
- return 0
+ return m.mode
}
func (m *mockFileInfo) ModTime() time.Time {
@@ -398,7 +403,7 @@
}
func (m *mockFileInfo) IsDir() bool {
- return m.isDir
+ return m.mode&os.ModeDir != 0
}
func (m *mockFileInfo) Sys() interface{} {
@@ -407,11 +412,11 @@
func (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: d.modTime,
permTime: d.permTime,
- isDir: true,
+ mode: os.ModeDir,
inodeNumber: d.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -420,11 +425,11 @@
func (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: f.modTime,
permTime: f.permTime,
- isDir: false,
+ mode: 0,
inodeNumber: f.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -432,11 +437,11 @@
func (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: l.modTime,
permTime: l.permTime,
- isDir: false,
+ mode: os.ModeSymlink,
inodeNumber: l.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -485,6 +490,16 @@
}
}
+func (m *MockFs) Stat(path string) (stats os.FileInfo, err error) {
+ // resolve symlinks
+ path, err = m.resolve(path, true)
+ if err != nil {
+ return nil, err
+ }
+
+ return m.Lstat(path)
+}
+
func (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) {
mockInfo, ok := info.(*mockFileInfo)
if ok {
diff --git a/finder/fs/fs_test.go b/finder/fs/fs_test.go
new file mode 100644
index 0000000..22a4d7a
--- /dev/null
+++ b/finder/fs/fs_test.go
@@ -0,0 +1,76 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// 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 fs
+
+import (
+ "os"
+ "testing"
+)
+
+func TestMockFs_LstatStatSymlinks(t *testing.T) {
+ // setup filesystem
+ filesystem := NewMockFs(nil)
+ Create(t, "/tmp/realdir/hi.txt", filesystem)
+ Create(t, "/tmp/realdir/ignoreme.txt", filesystem)
+
+ Link(t, "/tmp/links/dir", "../realdir", filesystem)
+ Link(t, "/tmp/links/file", "../realdir/hi.txt", filesystem)
+ Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ Link(t, "/tmp/links/recursive", "recursive", filesystem)
+
+ assertStat := func(t *testing.T, stat os.FileInfo, err error, wantName string, wantMode os.FileMode) {
+ t.Helper()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if g, w := stat.Name(), wantName; g != w {
+ t.Errorf("want name %q, got %q", w, g)
+ }
+ if g, w := stat.Mode(), wantMode; g != w {
+ t.Errorf("%s: want mode %q, got %q", wantName, w, g)
+ }
+ }
+
+ assertErr := func(t *testing.T, err error, wantErr string) {
+ if err == nil || err.Error() != wantErr {
+ t.Errorf("want error %q, got %q", wantErr, err)
+ }
+ }
+
+ stat, err := filesystem.Lstat("/tmp/links/dir")
+ assertStat(t, stat, err, "dir", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/dir")
+ assertStat(t, stat, err, "realdir", os.ModeDir)
+
+ stat, err = filesystem.Lstat("/tmp/links/file")
+ assertStat(t, stat, err, "file", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/file")
+ assertStat(t, stat, err, "hi.txt", 0)
+
+ stat, err = filesystem.Lstat("/tmp/links/broken")
+ assertStat(t, stat, err, "broken", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/broken")
+ assertErr(t, err, "stat /tmp/links/nothingHere: file does not exist")
+
+ stat, err = filesystem.Lstat("/tmp/links/recursive")
+ assertStat(t, stat, err, "recursive", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/recursive")
+ assertErr(t, err, "read /tmp/links/recursive: too many levels of symbolic links")
+}
diff --git a/finder/fs/test.go b/finder/fs/test.go
new file mode 100644
index 0000000..cb2140e
--- /dev/null
+++ b/finder/fs/test.go
@@ -0,0 +1,146 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// 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 fs
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "testing"
+ "time"
+)
+
+func Write(t *testing.T, path string, content string, filesystem *MockFs) {
+ parent := filepath.Dir(path)
+ filesystem.MkDirs(parent)
+ err := filesystem.WriteFile(path, []byte(content), 0777)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Create(t *testing.T, path string, filesystem *MockFs) {
+ Write(t, path, "hi", filesystem)
+}
+
+func Delete(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.Remove(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func RemoveAll(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.RemoveAll(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Move(t *testing.T, oldPath string, newPath string, filesystem *MockFs) {
+ err := filesystem.Rename(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Link(t *testing.T, newPath string, oldPath string, filesystem *MockFs) {
+ parentPath := filepath.Dir(newPath)
+ err := filesystem.MkDirs(parentPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ err = filesystem.Symlink(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Read(t *testing.T, path string, filesystem *MockFs) string {
+ reader, err := filesystem.Open(path)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ bytes, err := ioutil.ReadAll(reader)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return string(bytes)
+}
+
+func ModTime(t *testing.T, path string, filesystem *MockFs) time.Time {
+ stats, err := filesystem.Lstat(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return stats.ModTime()
+}
+
+func SetReadable(t *testing.T, path string, readable bool, filesystem *MockFs) {
+ err := filesystem.SetReadable(path, readable)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func SetReadErr(t *testing.T, path string, readErr error, filesystem *MockFs) {
+ err := filesystem.SetReadErr(path, readErr)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func AssertSameResponse(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
+ len(expected), expected, len(actual), actual)
+ }
+}
+
+func AssertSameStatCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect Stat calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
+
+func AssertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect ReadDir calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8b80871..00baa57 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -83,7 +83,6 @@
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables
- // (the actual substitution is implemented in GenerateAndroidBuildActions below)
//
// Available variables for substitution:
//
@@ -94,9 +93,6 @@
// $(depfile): a file to which dependencies will be written, if the depfile property is set to true
// $(genDir): the sandbox directory for this tool; contains $(out)
// $$: a literal $
- //
- // All files used must be declared as inputs (to ensure proper up-to-date checks).
- // Use "$(in)" directly in Cmd to ensure that all inputs used are declared.
Cmd *string
// Enable reading a file containing dependencies in gcc format after the command completes
diff --git a/java/androidmk.go b/java/androidmk.go
index e73b030..618e15d 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -719,6 +719,7 @@
func(entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile)
+ entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
},
diff --git a/java/app.go b/java/app.go
index 6a806a9..98bce94 100755
--- a/java/app.go
+++ b/java/app.go
@@ -79,6 +79,7 @@
properties AndroidAppSetProperties
packedOutput android.WritablePath
masterFile string
+ apkcertsFile android.ModuleOutPath
}
func (as *AndroidAppSet) Name() string {
@@ -130,6 +131,7 @@
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
+ as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
// We are assuming here that the master file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
@@ -142,16 +144,19 @@
// TODO(asmundak): do we support device features
ctx.Build(pctx,
android.BuildParams{
- Rule: extractMatchingApks,
- Description: "Extract APKs from APK set",
- Output: as.packedOutput,
- Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.packedOutput,
+ ImplicitOutput: as.apkcertsFile,
+ Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
"abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
"screen-densities": screenDensities,
"sdk-version": ctx.Config().PlatformSdkVersion(),
"stem": as.BaseModuleName(),
+ "apkcerts": as.apkcertsFile.String(),
+ "partition": as.PartitionTag(ctx.DeviceConfig()),
},
})
}
diff --git a/java/app_test.go b/java/app_test.go
index e0c5820..d4323bb 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -147,7 +147,7 @@
name: "foo",
set: "prebuilts/apks/app.apks",
prerelease: true,
- }`)
+ }`)
module := ctx.ModuleForTests("foo", "android_common")
const packedSplitApks = "foo.zip"
params := module.Output(packedSplitApks)
@@ -157,6 +157,9 @@
if s := params.Args["allow-prereleased"]; s != "true" {
t.Errorf("wrong allow-prereleased value: '%s', expected 'true'", s)
}
+ if s := params.Args["partition"]; s != "system" {
+ t.Errorf("wrong partition value: '%s', expected 'system'", s)
+ }
mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0]
actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"]
expectedMaster := []string{"foo.apk"}
diff --git a/java/builder.go b/java/builder.go
index a27e5c3..7318fcb 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,10 +120,11 @@
`${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
`-sdk-version=${sdk-version} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
+ `-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition")
turbine, turbineRE = remoteexec.StaticRules(pctx, "turbine",
blueprint.RuleParams{
diff --git a/java/config/config.go b/java/config/config.go
index bb5be3a..0fe74c8 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -28,14 +28,14 @@
var (
pctx = android.NewPackageContext("android/soong/java/config")
- // TODO(b/157640067): Don't depend on the legacy API by default in the long term.
- DefaultBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
- DefaultSystemModules = "legacy-core-platform-api-stubs-system-modules"
- DefaultLibraries = []string{"ext", "framework"}
- DefaultLambdaStubsLibrary = "core-lambda-stubs"
- SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
+ LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
+ LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules"
+ FrameworkLibraries = []string{"ext", "framework"}
+ DefaultLambdaStubsLibrary = "core-lambda-stubs"
+ SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
- DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+ DefaultMakeJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+ DefaultJacocoExcludeFilter = []string{"org.junit.**", "org.jacoco.**", "org.mockito.**"}
InstrumentFrameworkModules = []string{
"framework",
@@ -110,7 +110,7 @@
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
- pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh")
+ pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file.py")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh")
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 981a736..708a72a 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -25,9 +25,11 @@
}
func makeVarsProvider(ctx android.MakeVarsContext) {
- ctx.Strict("TARGET_DEFAULT_JAVA_LIBRARIES", strings.Join(DefaultLibraries, " "))
- ctx.Strict("TARGET_DEFAULT_BOOTCLASSPATH_LIBRARIES", strings.Join(DefaultBootclasspathLibraries, " "))
- ctx.Strict("DEFAULT_SYSTEM_MODULES", DefaultSystemModules)
+ ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
+
+ // These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
+ ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
+ ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
@@ -64,7 +66,7 @@
ctx.Strict("ZIPSYNC", "${ZipSyncCmd}")
ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}")
- ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
+ ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultMakeJacocoExcludeFilter, ","))
ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 73b897a..99bfb6d 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -440,16 +440,11 @@
func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
if ctx.Device() {
sdkDep := decodeSdkDep(ctx, sdkContext(j))
- if sdkDep.useDefaultLibs {
- ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
- if sdkDep.hasFrameworkLibs() {
- ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
- }
- } else if sdkDep.useModule {
+ if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+ ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
}
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index ce624bf..130b634 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -59,10 +59,9 @@
var _ hiddenAPIIntf = (*hiddenAPI)(nil)
-func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath,
+func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.ModuleOutPath,
implementationJar android.Path, uncompressDex bool) android.ModuleOutPath {
if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- name := ctx.ModuleName()
// Modules whose names are of the format <x>-hiddenapi provide hiddenapi information
// for the boot jar module <x>. Otherwise, the module provides information for itself.
@@ -90,7 +89,14 @@
// the gathered information in the generated dex file.
if name == bootJarName {
hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar")
- h.bootDexJarPath = dexJar
+
+ // More than one library with the same classes can be encoded but only one can
+ // be added to the global set of flags, otherwise it will result in duplicate
+ // classes which is an error. Therefore, only add the dex jar of one of them
+ // to the global set of flags.
+ if primary {
+ h.bootDexJarPath = dexJar
+ }
hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
dexJar = hiddenAPIJar
}
diff --git a/java/jacoco.go b/java/jacoco.go
index bce9822..9162161 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -25,6 +25,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/java/config"
)
var (
@@ -76,7 +77,8 @@
if err != nil {
ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error())
}
- excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter)
+ // Also include the default list of classes to exclude from instrumentation.
+ excludes, err := jacocoFiltersToSpecs(append(j.properties.Jacoco.Exclude_filter, config.DefaultJacocoExcludeFilter...))
if err != nil {
ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error())
}
diff --git a/java/java.go b/java/java.go
index 0a8eb99..0d46672 100644
--- a/java/java.go
+++ b/java/java.go
@@ -342,6 +342,12 @@
// otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
+ // The name of the module as used in build configuration.
+ //
+ // Allows a library to separate its actual name from the name used in
+ // build configuration, e.g.ctx.Config().BootJars().
+ ConfigurationName *string `blueprint:"mutated"`
+
// set the name of the output
Stem *string
@@ -591,7 +597,7 @@
}
type sdkDep struct {
- useModule, useFiles, useDefaultLibs, invalidVersion bool
+ useModule, useFiles, invalidVersion bool
// The modules that will be added to the bootclasspath when targeting 1.8 or lower
bootclasspath []string
@@ -600,7 +606,11 @@
// modules are to be used.
systemModules string
+ // The modules that will be added to the classpath regardless of the Java language level targeted
+ classpath []string
+
// The modules that will be added ot the classpath when targeting 1.9 or higher
+ // (normally these will be on the bootclasspath when targeting 1.8 or lower)
java9Classpath []string
frameworkResModule string
@@ -694,18 +704,15 @@
j.linter.deps(ctx)
sdkDep := decodeSdkDep(ctx, sdkContext(j))
- if sdkDep.useDefaultLibs {
- ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
- if sdkDep.hasFrameworkLibs() {
- ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
- }
- } else if sdkDep.useModule {
+ if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+ ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
+ ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+ }
+ if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
+ ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
}
}
if sdkDep.systemModules != "" {
@@ -1631,8 +1638,11 @@
return
}
+ configurationName := j.ConfigurationName()
+ primary := configurationName == ctx.ModuleName()
+
// Hidden API CSV generation and dex encoding
- dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+ dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
proptools.Bool(j.deviceProperties.Uncompress_dex))
// merge dex jar with resources if necessary
@@ -1909,6 +1919,10 @@
return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
}
+func (j *Module) ConfigurationName() string {
+ return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName())
+}
+
func (j *Module) JacocoReportClassesFile() android.Path {
return j.jacocoReportClassesFile
}
@@ -2903,6 +2917,7 @@
&appProperties{},
&appTestProperties{},
&overridableAppProperties{},
+ &testProperties{},
&ImportProperties{},
&AARImportProperties{},
&sdkLibraryProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 1d07e70..def42db 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -25,6 +25,7 @@
"strings"
"testing"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -171,6 +172,20 @@
}
}
+func checkModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ deps := []string{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ deps = append(deps, m.Name())
+ })
+ sort.Strings(deps)
+
+ if actual := deps; !reflect.DeepEqual(expected, actual) {
+ t.Errorf("expected %#q, found %#q", expected, actual)
+ }
+}
+
func TestJavaLinkType(t *testing.T) {
testJava(t, `
java_library {
@@ -630,6 +645,90 @@
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
}
}
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `prebuilt_sdklib.stubs.source.test`,
+ `prebuilt_sdklib.stubs.system`,
+ `prebuilt_sdklib.stubs.test`,
+ })
+}
+
+func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `sdklib.impl`,
+ // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
+ // dependency is added after prebuilts may have been renamed and so has to use
+ // the renamed name.
+ `sdklib.stubs`,
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ // This should be sdklib.stubs but is switched to the prebuilt because it is preferred.
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.xml`,
+ })
}
func TestDefaults(t *testing.T) {
@@ -1379,6 +1478,28 @@
`)
}
+func TestJavaSdkLibrary_Deps(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+}
+
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
testJava(t, `
java_sdk_library_import {
diff --git a/java/kotlin.go b/java/kotlin.go
index 673970b..e3356be 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -31,7 +31,9 @@
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@@ -74,7 +76,7 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
@@ -93,7 +95,9 @@
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -162,7 +166,7 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(),
diff --git a/java/sdk.go b/java/sdk.go
index 2a08f32..c4861e3 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -94,9 +94,9 @@
case sdkCorePlatform:
return "core_platform"
case sdkModule:
- return "module"
+ return "module-lib"
case sdkSystemServer:
- return "system_server"
+ return "system-server"
default:
return "invalid"
}
@@ -412,7 +412,10 @@
switch sdkVersion.kind {
case sdkPrivate:
return sdkDep{
- useDefaultLibs: true,
+ useModule: true,
+ systemModules: config.LegacyCorePlatformSystemModules,
+ bootclasspath: config.LegacyCorePlatformBootclasspathLibraries,
+ classpath: config.FrameworkLibraries,
frameworkResModule: "framework-res",
}
case sdkNone:
@@ -434,9 +437,10 @@
}
case sdkCorePlatform:
return sdkDep{
- useDefaultLibs: true,
- frameworkResModule: "framework-res",
- noFrameworksLibs: true,
+ useModule: true,
+ systemModules: config.LegacyCorePlatformSystemModules,
+ bootclasspath: config.LegacyCorePlatformBootclasspathLibraries,
+ noFrameworksLibs: true,
}
case sdkPublic:
return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 91869ed..8f8f8ce 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1087,15 +1087,22 @@
// Creates the implementation java library
func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
+
+ moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
+
props := struct {
- Name *string
- Visibility []string
- Instrument bool
+ Name *string
+ Visibility []string
+ Instrument bool
+ ConfigurationName *string
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: module.sdkLibraryProperties.Impl_library_visibility,
// Set the instrument property to ensure it is instrumented when instrumentation is required.
Instrument: true,
+
+ // Make the created library behave as if it had the same name as this module.
+ ConfigurationName: moduleNamePtr,
}
properties := []interface{}{
diff --git a/java/sdk_test.go b/java/sdk_test.go
index e5d322c..773a70c 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -49,27 +49,27 @@
}{
{
name: "default",
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
- java8classpath: config.DefaultLibraries,
- java9classpath: config.DefaultLibraries,
+ bootclasspath: config.LegacyCorePlatformBootclasspathLibraries,
+ system: config.LegacyCorePlatformSystemModules,
+ java8classpath: config.FrameworkLibraries,
+ java9classpath: config.FrameworkLibraries,
aidl: "-Iframework/aidl",
},
{
name: `sdk_version:"core_platform"`,
properties: `sdk_version:"core_platform"`,
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
+ bootclasspath: config.LegacyCorePlatformBootclasspathLibraries,
+ system: config.LegacyCorePlatformSystemModules,
java8classpath: []string{},
aidl: "",
},
{
name: "blank sdk version",
properties: `sdk_version: "",`,
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
- java8classpath: config.DefaultLibraries,
- java9classpath: config.DefaultLibraries,
+ bootclasspath: config.LegacyCorePlatformBootclasspathLibraries,
+ system: config.LegacyCorePlatformSystemModules,
+ java8classpath: config.FrameworkLibraries,
+ java9classpath: config.FrameworkLibraries,
aidl: "-Iframework/aidl",
},
{
diff --git a/java/testing.go b/java/testing.go
index 6fc10da..f5688e6 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -197,6 +197,7 @@
systemModules := []string{
"core-current-stubs-system-modules",
"legacy-core-platform-api-stubs-system-modules",
+ "stable-core-platform-api-stubs-system-modules",
}
for _, extra := range systemModules {
diff --git a/rust/Android.bp b/rust/Android.bp
index b06ea8e..d56de87 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -9,24 +9,26 @@
],
srcs: [
"androidmk.go",
- "compiler.go",
- "coverage.go",
"binary.go",
"builder.go",
+ "clippy.go",
+ "compiler.go",
+ "coverage.go",
"library.go",
"prebuilt.go",
"proc_macro.go",
- "project_json.go",
+ "project_json.go",
"rust.go",
"test.go",
"testing.go",
],
testSrcs: [
"binary_test.go",
+ "clippy_test.go",
"compiler_test.go",
"coverage_test.go",
"library_test.go",
- "project_json_test.go",
+ "project_json_test.go",
"rust_test.go",
"test_test.go",
],
diff --git a/rust/OWNERS b/rust/OWNERS
index afd06e4..b5b795c 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,5 +1,5 @@
# Additional owner/reviewers for rust rules, including parent directory owners.
-per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com
+per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
# Limited owners/reviewers of the allowed list.
-per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
+per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, mmaurer@google.com, srhines@google.com
diff --git a/rust/binary.go b/rust/binary.go
index 56d6f0b..a1cd410 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -131,3 +131,11 @@
func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath {
return binary.coverageOutputZipFile
}
+
+func (binary *binaryDecorator) autoDep() autoDep {
+ if binary.preferDynamic() {
+ return dylibAutoDep
+ } else {
+ return rlibAutoDep
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
index 7dbb59d..16d7306 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -39,6 +39,18 @@
},
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+ _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+ clippyDriver = pctx.AndroidStaticRule("clippy",
+ blueprint.RuleParams{
+ Command: "$clippyCmd " +
+ // Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+ // Use the metadata output as it has the smallest footprint.
+ "--emit metadata -o $out $in ${libFlags} " +
+ "$rustcFlags $clippyFlags",
+ CommandDeps: []string{"$clippyCmd"},
+ },
+ "rustcFlags", "libFlags", "clippyFlags")
+
zip = pctx.AndroidStaticRule("zip",
blueprint.RuleParams{
Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
@@ -57,38 +69,38 @@
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
}
-func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) buildOutput {
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", linkDirs)
}
-func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", linkDirs)
}
-func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", linkDirs)
}
-func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) buildOutput {
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", linkDirs)
}
-func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) buildOutput {
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", linkDirs)
}
-func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
- flags Flags, outputFile android.WritablePath, includeDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
+ flags Flags, outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", linkDirs)
}
func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -99,8 +111,8 @@
return paths
}
-func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crate_type string, includeDirs []string) buildOutput {
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, crate_type string, linkDirs []string) buildOutput {
var inputs android.Paths
var implicits android.Paths
@@ -109,8 +121,8 @@
var implicitOutputs android.WritablePaths
output.outputFile = outputFile
- crate_name := ctx.(ModuleContext).CrateName()
- targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+ crate_name := ctx.RustModule().CrateName()
+ targetTriple := ctx.toolchain().RustTriple()
inputs = append(inputs, main)
@@ -125,12 +137,10 @@
rustcFlags = append(rustcFlags, "--target="+targetTriple)
linkFlags = append(linkFlags, "-target "+targetTriple)
}
- // TODO once we have static libraries in the host prebuilt .bp, this
- // should be unconditionally added.
- if !(ctx.Host() && ctx.TargetPrimary()) {
- // If we're not targeting the host primary arch, do not use an implicit sysroot
- rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
- }
+
+ // Suppress an implicit sysroot
+ rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
+
// Collect linker flags
linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
linkFlags = append(linkFlags, flags.LinkFlags...)
@@ -146,7 +156,7 @@
libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
}
- for _, path := range includeDirs {
+ for _, path := range linkDirs {
libFlags = append(libFlags, "-L "+path)
}
@@ -179,6 +189,25 @@
output.coverageFile = gcnoFile
}
+ if flags.Clippy {
+ clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: clippyDriver,
+ Description: "clippy " + main.Rel(),
+ Output: clippyFile,
+ ImplicitOutputs: nil,
+ Inputs: inputs,
+ Implicits: implicits,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "clippyFlags": strings.Join(flags.ClippyFlags, " "),
+ },
+ })
+ // Declare the clippy build as an implicit dependency of the original crate.
+ implicits = append(implicits, clippyFile)
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: rustc,
Description: "rustc " + main.Rel(),
@@ -198,7 +227,7 @@
return output
}
-func TransformCoverageFilesToZip(ctx android.ModuleContext,
+func TransformCoverageFilesToZip(ctx ModuleContext,
covFiles android.Paths, baseName string) android.OptionalPath {
if len(covFiles) > 0 {
diff --git a/rust/clippy.go b/rust/clippy.go
new file mode 100644
index 0000000..e1f567d
--- /dev/null
+++ b/rust/clippy.go
@@ -0,0 +1,42 @@
+// Copyright 2020 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 rust
+
+import (
+ "android/soong/rust/config"
+)
+
+type ClippyProperties struct {
+ // whether to run clippy.
+ Clippy *bool
+}
+
+type clippy struct {
+ Properties ClippyProperties
+}
+
+func (c *clippy) props() []interface{} {
+ return []interface{}{&c.Properties}
+}
+
+func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+ if c.Properties.Clippy != nil && !*c.Properties.Clippy {
+ return flags, deps
+ }
+ enabled, lints := config.ClippyLintsForDir(ctx.ModuleDir())
+ flags.Clippy = enabled
+ flags.ClippyFlags = append(flags.ClippyFlags, lints)
+ return flags, deps
+}
diff --git a/rust/clippy_test.go b/rust/clippy_test.go
new file mode 100644
index 0000000..3144173
--- /dev/null
+++ b/rust/clippy_test.go
@@ -0,0 +1,46 @@
+// Copyright 2020 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 rust
+
+import (
+ "testing"
+)
+
+func TestClippy(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ rust_library {
+ name: "libfoobar",
+ srcs: ["foo.rs"],
+ crate_name: "foobar",
+ clippy: false,
+ }`)
+
+ ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Output("libfoo.dylib.so")
+ fooClippy := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
+ if fooClippy.Rule.String() != "android/soong/rust.clippy" {
+ t.Errorf("Clippy output (default) for libfoo was not generated: %+v", fooClippy)
+ }
+
+ ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").Output("libfoobar.dylib.so")
+ foobarClippy := ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
+ if foobarClippy.Rule != nil {
+ t.Errorf("Clippy output for libfoobar is not empty")
+ }
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index efc1ce4..92a3b07 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -28,10 +28,6 @@
return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
}
-func getDenyWarnings(compiler *baseCompiler) bool {
- return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings)
-}
-
func (compiler *baseCompiler) setNoStdlibs() {
compiler.Properties.No_stdlibs = proptools.BoolPtr(true)
}
@@ -56,8 +52,8 @@
// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
Srcs []string `android:"path,arch_variant"`
- // whether to pass "-D warnings" to rustc. Defaults to true.
- Deny_warnings *bool
+ // whether to suppress the standard lint flags - default to false
+ No_lint *bool
// flags to pass to rustc
Flags []string `android:"path,arch_variant"`
@@ -71,6 +67,9 @@
// list of rust dylib crate dependencies
Dylibs []string `android:"arch_variant"`
+ // list of rust automatic crate dependencies
+ Rustlibs []string `android:"arch_variant"`
+
// list of rust proc_macro crate dependencies
Proc_macros []string `android:"arch_variant"`
@@ -104,8 +103,6 @@
type baseCompiler struct {
Properties BaseCompilerProperties
- depFlags []string
- linkDirs []string
coverageFile android.Path //rustc generates a single gcno file
// Install related
@@ -145,8 +142,8 @@
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
- if getDenyWarnings(compiler) {
- flags.RustFlags = append(flags.RustFlags, "-D warnings")
+ if !Bool(compiler.Properties.No_lint) {
+ flags.RustFlags = append(flags.RustFlags, config.RustcLintsForDir(ctx.ModuleDir()))
}
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
@@ -182,6 +179,7 @@
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
+ deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
@@ -193,17 +191,7 @@
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
- // This check is technically insufficient - on the host, where
- // static linking is the default, if one of our static
- // dependencies uses a dynamic library, we need to dynamically
- // link the stdlib as well.
- if (len(deps.Dylibs) > 0) || ctx.Device() {
- // Dynamically linked stdlib
- deps.Dylibs = append(deps.Dylibs, stdlib)
- } else if ctx.Host() && !ctx.TargetPrimary() {
- // Otherwise use the static in-tree stdlib for host secondary arch
- deps.Rlibs = append(deps.Rlibs, stdlib+".static")
- }
+ deps.Rustlibs = append(deps.Rustlibs, stdlib)
}
}
return deps
@@ -253,7 +241,7 @@
}
func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
- stem := ctx.baseModuleName()
+ stem := ctx.ModuleName()
if String(compiler.Properties.Stem) != "" {
stem = String(compiler.Properties.Stem)
}
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 5026da3..bcfac7c 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -9,6 +9,7 @@
"arm_device.go",
"arm64_device.go",
"global.go",
+ "lints.go",
"toolchain.go",
"allowed_list.go",
"x86_darwin_host.go",
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index a339050..0204cd2 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -15,13 +15,15 @@
"rust_library",
"rust_library_dylib",
"rust_library_rlib",
- "rust_library_shared",
- "rust_library_static",
+ "rust_ffi",
+ "rust_ffi_shared",
+ "rust_ffi_static",
"rust_library_host",
"rust_library_host_dylib",
"rust_library_host_rlib",
- "rust_library_host_shared",
- "rust_library_host_static",
+ "rust_ffi_host",
+ "rust_ffi_host_shared",
+ "rust_ffi_host_static",
"rust_proc_macro",
"rust_test",
"rust_test_host",
diff --git a/rust/config/global.go b/rust/config/global.go
index 63624c0..e1b1775 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.43.0"
+ RustDefaultVersion = "1.44.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
@@ -32,8 +32,6 @@
"libtest",
}
- DefaultDenyWarnings = true
-
GlobalRustFlags = []string{
"--remap-path-prefix $$(pwd)=",
"-C codegen-units=1",
diff --git a/rust/config/lints.go b/rust/config/lints.go
new file mode 100644
index 0000000..529d094
--- /dev/null
+++ b/rust/config/lints.go
@@ -0,0 +1,150 @@
+// Copyright 2020 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+// Overarching principles for Rust lints on Android:
+// The Android build system tries to avoid reporting warnings during the build.
+// Therefore, by default, we upgrade warnings to denials. For some of these
+// lints, an allow exception is setup, using the variables below.
+// There are different default lints depending on the repository location (see
+// DefaultLocalClippyChecks).
+// The lints are split into two categories. The first one contains the built-in
+// lints (https://doc.rust-lang.org/rustc/lints/index.html). The second is
+// specific to Clippy lints (https://rust-lang.github.io/rust-clippy/master/).
+//
+// When developing a module, it is possible to use the `no_lint` property to
+// disable the built-in lints configuration. It is also possible to set
+// `clippy` to false to disable the clippy verification. Expect some
+// questioning during review if you enable one of these options. For external/
+// code, if you need to use them, it is likely a bug. Otherwise, it may be
+// useful to add an exception (that is, move a lint from deny to allow).
+var (
+ // Default Rust lints that applies to Google-authored modules.
+ defaultRustcLints = []string{
+ "-A deprecated",
+ "-D missing-docs",
+ "-D warnings",
+ }
+ // Default Clippy lints. These are applied on top of defaultRustcLints.
+ // It should be assumed that any warning lint will be promoted to a
+ // deny.
+ defaultClippyLints = []string{
+ "-A clippy::type-complexity",
+ }
+
+ // Rust lints for vendor code.
+ defaultRustcVendorLints = []string{
+ "-A deprecated",
+ "-D warnings",
+ }
+ // Clippy lints for vendor source. These are applied on top of
+ // defaultRustcVendorLints. It should be assumed that any warning lint
+ // will be promoted to a deny.
+ defaultClippyVendorLints = []string{
+ "-A clippy::complexity",
+ "-A clippy::perf",
+ "-A clippy::style",
+ }
+
+ // For prebuilts/ and external/, no linting is expected. If a warning
+ // or a deny is reported, it should be fixed upstream.
+ allowAllLints = []string{
+ "--cap-lints allow",
+ }
+)
+
+func init() {
+ // Default Rust lints. These apply to all Google-authored modules.
+ pctx.VariableFunc("RustDefaultLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_DEFAULT_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultRustcLints, " ")
+ })
+ pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultClippyLints, " ")
+ })
+
+ // Rust lints that only applies to external code.
+ pctx.VariableFunc("RustVendorLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_VENDOR_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultRustcVendorLints, " ")
+ })
+ pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultClippyVendorLints, " ")
+ })
+ pctx.StaticVariable("RustAllowAllLints", strings.Join(allowAllLints, " "))
+}
+
+type PathBasedClippyConfig struct {
+ PathPrefix string
+ RustcConfig string
+ ClippyEnabled bool
+ ClippyConfig string
+}
+
+const noLint = ""
+const rustcDefault = "${config.RustDefaultLints}"
+const rustcVendor = "${config.RustVendorLints}"
+const rustcAllowAll = "${config.RustAllowAllLints}"
+const clippyDefault = "${config.ClippyDefaultLints}"
+const clippyVendor = "${config.ClippyVendorLints}"
+
+// This is a map of local path prefixes to a set of parameters for the linting:
+// - a string for the lints to apply to rustc.
+// - a boolean to indicate if clippy should be executed.
+// - a string for the lints to apply to clippy.
+// The first entry matching will be used.
+var DefaultLocalClippyChecks = []PathBasedClippyConfig{
+ {"external/", rustcAllowAll, false, noLint},
+ {"hardware/", rustcVendor, true, clippyVendor},
+ {"prebuilts/", rustcAllowAll, false, noLint},
+ {"vendor/google", rustcDefault, true, clippyDefault},
+ {"vendor/", rustcVendor, true, clippyVendor},
+}
+
+// ClippyLintsForDir returns a boolean if Clippy should be executed and if so, the lints to be used.
+func ClippyLintsForDir(dir string) (bool, string) {
+ for _, pathCheck := range DefaultLocalClippyChecks {
+ if strings.HasPrefix(dir, pathCheck.PathPrefix) {
+ return pathCheck.ClippyEnabled, pathCheck.ClippyConfig
+ }
+ }
+ return true, clippyDefault
+}
+
+// RustcLintsForDir returns the standard lints to be used for a repository.
+func RustcLintsForDir(dir string) string {
+ for _, pathCheck := range DefaultLocalClippyChecks {
+ if strings.HasPrefix(dir, pathCheck.PathPrefix) {
+ return pathCheck.RustcConfig
+ }
+ }
+ return rustcDefault
+}
diff --git a/rust/coverage.go b/rust/coverage.go
index 4e3977b..223ba4f 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -67,6 +67,6 @@
// Host coverage not yet supported.
} else {
// Update useSdk and sdkVersion args if Rust modules become SDK aware.
- cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), false, "")
+ cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
}
}
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 27acad3..357c2e8 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -105,6 +105,12 @@
rlibs: ["librlib"],
crate_name: "foo",
}
+ rust_ffi_static {
+ name: "libbaz",
+ srcs: ["foo.rs"],
+ rlibs: ["librlib"],
+ crate_name: "baz",
+ }
rust_library_rlib {
name: "librlib",
srcs: ["foo.rs"],
@@ -113,17 +119,17 @@
rust_binary {
name: "fizz",
rlibs: ["librlib"],
- static_libs: ["libfoo"],
+ static_libs: ["libbaz"],
srcs: ["foo.rs"],
}
cc_binary {
name: "buzz",
- static_libs: ["libfoo"],
+ static_libs: ["libbaz"],
srcs: ["foo.c"],
}
cc_library {
name: "libbar",
- static_libs: ["libfoo"],
+ static_libs: ["libbaz"],
compile_multilib: "64",
srcs: ["foo.c"],
}`)
@@ -149,7 +155,7 @@
// Make sure the expected inputs are provided to the zip rule.
if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
- !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") ||
+ !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") ||
!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
}
@@ -158,11 +164,11 @@
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
}
if !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_cov/obj/foo.gcno") ||
- !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
+ !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
t.Fatalf("missing expected coverage files for cc 'buzz' binary: %#v", buzzZipInputs)
}
if !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/obj/foo.gcno") ||
- !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
+ !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
t.Fatalf("missing expected coverage files for cc 'libbar' library: %#v", libbarZipInputs)
}
}
diff --git a/rust/library.go b/rust/library.go
index 3c948ea..8b8e797 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -19,7 +19,6 @@
"strings"
"android/soong/android"
- "android/soong/rust/config"
)
func init() {
@@ -29,14 +28,17 @@
android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
- android.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
- android.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
- android.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
- android.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
+ android.RegisterModuleType("rust_ffi", RustFFIFactory)
+ android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
+ android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
+ android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
+ android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
}
type VariantLibraryProperties struct {
- Enabled *bool `android:"arch_variant"`
+ Enabled *bool `android:"arch_variant"`
+ Srcs []string `android:"path,arch_variant"`
}
type LibraryCompilerProperties struct {
@@ -71,6 +73,7 @@
type libraryDecorator struct {
*baseCompiler
+ *flagExporter
Properties LibraryCompilerProperties
MutatedProperties LibraryMutatedProperties
@@ -96,6 +99,8 @@
setStatic()
// Build a specific library variant
+ BuildOnlyFFI()
+ BuildOnlyRust()
BuildOnlyRlib()
BuildOnlyDylib()
BuildOnlyStatic()
@@ -106,22 +111,6 @@
return true
}
-func (library *libraryDecorator) exportedDirs() []string {
- return library.linkDirs
-}
-
-func (library *libraryDecorator) exportedDepFlags() []string {
- return library.depFlags
-}
-
-func (library *libraryDecorator) reexportDirs(dirs ...string) {
- library.linkDirs = android.FirstUniqueStrings(append(library.linkDirs, dirs...))
-}
-
-func (library *libraryDecorator) reexportDepFlags(flags ...string) {
- library.depFlags = android.FirstUniqueStrings(append(library.depFlags, flags...))
-}
-
func (library *libraryDecorator) rlib() bool {
return library.MutatedProperties.VariantIsRlib
}
@@ -182,12 +171,31 @@
library.MutatedProperties.VariantIsDylib = false
}
+func (library *libraryDecorator) autoDep() autoDep {
+ if library.rlib() || library.static() {
+ return rlibAutoDep
+ } else if library.dylib() || library.shared() {
+ return dylibAutoDep
+ } else {
+ return rlibAutoDep
+ }
+}
+
var _ compiler = (*libraryDecorator)(nil)
var _ libraryInterface = (*libraryDecorator)(nil)
+var _ exportedFlagsProducer = (*libraryDecorator)(nil)
-// rust_library produces all variants.
+// rust_library produces all rust variants.
func RustLibraryFactory() android.Module {
- module, _ := NewRustLibrary(android.HostAndDeviceSupported)
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRust()
+ return module.Init()
+}
+
+// rust_ffi produces all ffi variants.
+func RustFFIFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyFFI()
return module.Init()
}
@@ -205,23 +213,31 @@
return module.Init()
}
-// rust_library_shared produces a shared library.
-func RustLibrarySharedFactory() android.Module {
+// rust_ffi_shared produces a shared library.
+func RustFFISharedFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyShared()
return module.Init()
}
-// rust_library_static produces a static library.
-func RustLibraryStaticFactory() android.Module {
+// rust_ffi_static produces a static library.
+func RustFFIStaticFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
return module.Init()
}
-// rust_library_host produces all variants.
+// rust_library_host produces all rust variants.
func RustLibraryHostFactory() android.Module {
- module, _ := NewRustLibrary(android.HostSupported)
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRust()
+ return module.Init()
+}
+
+// rust_ffi_host produces all FFI variants.
+func RustFFIHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyFFI()
return module.Init()
}
@@ -239,44 +255,60 @@
return module.Init()
}
-// rust_library_static_host produces a static library.
-func RustLibraryStaticHostFactory() android.Module {
+// rust_ffi_static_host produces a static library.
+func RustFFIStaticHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyStatic()
return module.Init()
}
-// rust_library_shared_host produces an shared library.
-func RustLibrarySharedHostFactory() android.Module {
+// rust_ffi_shared_host produces an shared library.
+func RustFFISharedHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyShared()
return module.Init()
}
+func (library *libraryDecorator) BuildOnlyFFI() {
+ library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildRlib = false
+ library.MutatedProperties.BuildShared = true
+ library.MutatedProperties.BuildStatic = true
+}
+
+func (library *libraryDecorator) BuildOnlyRust() {
+ library.MutatedProperties.BuildDylib = true
+ library.MutatedProperties.BuildRlib = true
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = false
+}
+
func (library *libraryDecorator) BuildOnlyDylib() {
+ library.MutatedProperties.BuildDylib = true
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = false
-
}
func (library *libraryDecorator) BuildOnlyRlib() {
library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = false
}
func (library *libraryDecorator) BuildOnlyStatic() {
- library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
-
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = true
}
func (library *libraryDecorator) BuildOnlyShared() {
- library.MutatedProperties.BuildStatic = false
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildStatic = false
+ library.MutatedProperties.BuildShared = true
}
func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -284,12 +316,13 @@
library := &libraryDecorator{
MutatedProperties: LibraryMutatedProperties{
- BuildDylib: true,
- BuildRlib: true,
- BuildShared: true,
- BuildStatic: true,
+ BuildDylib: false,
+ BuildRlib: false,
+ BuildShared: false,
+ BuildStatic: false,
},
baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
+ flagExporter: NewFlagExporter(),
}
module.compiler = library
@@ -304,15 +337,6 @@
}
func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
-
- // TODO(b/155498724) Remove if C static libraries no longer require libstd as an rlib dependency.
- if !ctx.Host() && library.static() {
- library.setNoStdlibs()
- for _, stdlib := range config.Stdlibs {
- deps.Rlibs = append(deps.Rlibs, stdlib+".static")
- }
- }
-
deps = library.baseCompiler.compilerDeps(ctx, deps)
if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
@@ -329,7 +353,7 @@
}
func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
- flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName())
+ flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
flags = library.baseCompiler.compilerFlags(ctx, flags)
if library.shared() || library.static() {
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
@@ -391,8 +415,8 @@
library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
if library.rlib() || library.dylib() {
- library.reexportDirs(deps.linkDirs...)
- library.reexportDepFlags(deps.depFlags...)
+ library.exportLinkDirs(deps.linkDirs...)
+ library.exportDepFlags(deps.depFlags...)
}
library.unstrippedOutputFile = outputFile
diff --git a/rust/library_test.go b/rust/library_test.go
index 9d2f6c0..8a91cf1 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -29,13 +29,18 @@
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
- }`)
+ }
+ rust_ffi_host {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo"
+ }`)
// Test all variants are being built.
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
- libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Output("libfoo.a")
- libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
rlibCrateType := "rlib"
dylibCrateType := "dylib"
@@ -119,7 +124,7 @@
func TestSharedLibrary(t *testing.T) {
ctx := testRust(t, `
- rust_library {
+ rust_ffi_shared {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
@@ -138,3 +143,50 @@
libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
}
+
+// Test that variants pull in the right type of rustlib autodep
+func TestAutoDeps(t *testing.T) {
+
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libbar",
+ srcs: ["bar.rs"],
+ crate_name: "bar",
+ }
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ rustlibs: ["libbar"],
+ }
+ rust_ffi_host {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ rustlibs: ["libbar"],
+ }`)
+
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
+
+ for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
+ if !android.InList("libbar", static.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("libbar not present as static dependency in static lib")
+ }
+ if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("libbar present as dynamic dependency in static lib")
+ }
+ }
+
+ for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
+ if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("libbar not present as dynamic dependency in dynamic lib")
+ }
+ if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("libbar present as static dependency in dynamic lib")
+ }
+
+ }
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 1d97650..67d649d 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -19,12 +19,16 @@
)
func init() {
+ android.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
android.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+ android.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
}
type PrebuiltProperties struct {
// path to the prebuilt file
Srcs []string `android:"path,arch_variant"`
+ // directories containing associated rlib dependencies
+ Link_dirs []string `android:"path,arch_variant"`
}
type prebuiltLibraryDecorator struct {
@@ -33,32 +37,65 @@
}
var _ compiler = (*prebuiltLibraryDecorator)(nil)
+var _ exportedFlagsProducer = (*prebuiltLibraryDecorator)(nil)
+
+func PrebuiltLibraryFactory() android.Module {
+ module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ return module.Init()
+}
func PrebuiltDylibFactory() android.Module {
module, _ := NewPrebuiltDylib(android.HostAndDeviceSupported)
return module.Init()
}
-func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+func PrebuiltRlibFactory() android.Module {
+ module, _ := NewPrebuiltRlib(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
module, library := NewRustLibrary(hod)
- library.BuildOnlyDylib()
+ library.BuildOnlyRust()
library.setNoStdlibs()
- library.setDylib()
prebuilt := &prebuiltLibraryDecorator{
libraryDecorator: library,
}
module.compiler = prebuilt
- module.AddProperties(&library.Properties)
+ return module, prebuilt
+}
+
+func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyDylib()
+ library.setNoStdlibs()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
+ return module, prebuilt
+}
+
+func NewPrebuiltRlib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyRlib()
+ library.setNoStdlibs()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
return module, prebuilt
}
func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} {
- return append(prebuilt.baseCompiler.compilerProps(),
+ return append(prebuilt.libraryDecorator.compilerProps(),
&prebuilt.Properties)
}
func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
- srcPath := srcPathFromModuleSrcs(ctx, prebuilt.Properties.Srcs)
+ prebuilt.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
+
+ srcPath := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
prebuilt.unstrippedOutputFile = srcPath
@@ -73,3 +110,15 @@
func (prebuilt *prebuiltLibraryDecorator) nativeCoverage() bool {
return false
}
+
+func (prebuilt *prebuiltLibraryDecorator) prebuiltSrcs() []string {
+ srcs := prebuilt.Properties.Srcs
+ if prebuilt.rlib() {
+ srcs = append(srcs, prebuilt.libraryDecorator.Properties.Rlib.Srcs...)
+ }
+ if prebuilt.dylib() {
+ srcs = append(srcs, prebuilt.libraryDecorator.Properties.Dylib.Srcs...)
+ }
+
+ return srcs
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 42c8537..2719161 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -27,6 +27,7 @@
type procMacroDecorator struct {
*baseCompiler
+ *flagExporter
Properties ProcMacroCompilerProperties
}
@@ -35,6 +36,7 @@
}
var _ compiler = (*procMacroDecorator)(nil)
+var _ exportedFlagsProducer = (*procMacroDecorator)(nil)
func ProcMacroFactory() android.Module {
module, _ := NewProcMacro(android.HostSupportedNoCross)
@@ -46,6 +48,7 @@
procMacro := &procMacroDecorator{
baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
+ flagExporter: NewFlagExporter(),
}
module.compiler = procMacro
@@ -76,3 +79,7 @@
return stem + String(procMacro.baseCompiler.Properties.Suffix)
}
+
+func (procMacro *procMacroDecorator) autoDep() autoDep {
+ return rlibAutoDep
+}
diff --git a/rust/rust.go b/rust/rust.go
index 7b82b1f..72301a7 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -49,8 +49,10 @@
GlobalLinkFlags []string // Flags that apply globally to linker
RustFlags []string // Flags that apply to rust
LinkFlags []string // Flags that apply to linker
+ ClippyFlags []string // Flags that apply to clippy-driver, during the linting
Toolchain config.Toolchain
Coverage bool
+ Clippy bool
}
type BaseProperties struct {
@@ -75,6 +77,7 @@
compiler compiler
coverage *coverage
+ clippy *clippy
cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool
outputFile android.OptionalPath
@@ -214,6 +217,7 @@
type Deps struct {
Dylibs []string
Rlibs []string
+ Rustlibs []string
ProcMacros []string
SharedLibs []string
StaticLibs []string
@@ -258,6 +262,43 @@
nativeCoverage() bool
}
+type exportedFlagsProducer interface {
+ exportedLinkDirs() []string
+ exportedDepFlags() []string
+ exportLinkDirs(...string)
+ exportDepFlags(...string)
+}
+
+type flagExporter struct {
+ depFlags []string
+ linkDirs []string
+}
+
+func (flagExporter *flagExporter) exportedLinkDirs() []string {
+ return flagExporter.linkDirs
+}
+
+func (flagExporter *flagExporter) exportedDepFlags() []string {
+ return flagExporter.depFlags
+}
+
+func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
+ flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
+}
+
+func (flagExporter *flagExporter) exportDepFlags(flags ...string) {
+ flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...))
+}
+
+var _ exportedFlagsProducer = (*flagExporter)(nil)
+
+func NewFlagExporter() *flagExporter {
+ return &flagExporter{
+ depFlags: []string{},
+ linkDirs: []string{},
+ }
+}
+
func (mod *Module) isCoverageVariant() bool {
return mod.coverage.Properties.IsCoverageVariant
}
@@ -306,6 +347,7 @@
&PrebuiltProperties{},
&TestProperties{},
&cc.CoverageProperties{},
+ &ClippyProperties{},
)
android.InitDefaultsModule(module)
@@ -411,7 +453,7 @@
func (mod *Module) StubsVersions() []string {
// For now, Rust has no stubs versions.
if mod.compiler != nil {
- if _, ok := mod.compiler.(*libraryDecorator); ok {
+ if _, ok := mod.compiler.(libraryInterface); ok {
return []string{}
}
}
@@ -435,6 +477,9 @@
func (mod *Module) CoverageFiles() android.Paths {
if mod.compiler != nil {
+ if !mod.compiler.nativeCoverage() {
+ return android.Paths{}
+ }
if library, ok := mod.compiler.(*libraryDecorator); ok {
if library.coverageFile != nil {
return android.Paths{library.coverageFile}
@@ -456,6 +501,9 @@
if mod.coverage != nil {
mod.AddProperties(mod.coverage.props()...)
}
+ if mod.clippy != nil {
+ mod.AddProperties(mod.clippy.props()...)
+ }
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
@@ -487,6 +535,7 @@
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
module := newBaseModule(hod, multilib)
module.coverage = &coverage{}
+ module.clippy = &clippy{}
return module
}
@@ -506,39 +555,50 @@
}
type ModuleContextIntf interface {
+ RustModule() *Module
toolchain() config.Toolchain
- baseModuleName() string
- CrateName() string
- nativeCoverage() bool
}
type depsContext struct {
android.BottomUpMutatorContext
- moduleContextImpl
}
type moduleContext struct {
android.ModuleContext
- moduleContextImpl
}
-func (ctx *moduleContextImpl) nativeCoverage() bool {
- return ctx.mod.nativeCoverage()
+type baseModuleContext struct {
+ android.BaseModuleContext
+}
+
+func (ctx *moduleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *moduleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *depsContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *depsContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *baseModuleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *baseModuleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
}
func (mod *Module) nativeCoverage() bool {
return mod.compiler != nil && mod.compiler.nativeCoverage()
}
-type moduleContextImpl struct {
- mod *Module
- ctx BaseModuleContext
-}
-
-func (ctx *moduleContextImpl) toolchain() config.Toolchain {
- return ctx.mod.toolchain(ctx.ctx)
-}
-
func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
if mod.cachedToolchain == nil {
mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
@@ -552,11 +612,7 @@
func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
ModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
toolchain := mod.toolchain(ctx)
@@ -576,6 +632,9 @@
if mod.coverage != nil {
flags, deps = mod.coverage.flags(ctx, flags, deps)
}
+ if mod.clippy != nil {
+ flags, deps = mod.clippy.flags(ctx, flags, deps)
+ }
if mod.compiler != nil {
outputFile := mod.compiler.compile(ctx, flags, deps)
@@ -599,6 +658,7 @@
deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
+ deps.Rustlibs = android.LastUniqueStrings(deps.Rustlibs)
deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
@@ -607,14 +667,6 @@
}
-func (ctx *moduleContextImpl) baseModuleName() string {
- return ctx.mod.ModuleBase.BaseModuleName()
-}
-
-func (ctx *moduleContextImpl) CrateName() string {
- return ctx.mod.CrateName()
-}
-
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
@@ -629,6 +681,20 @@
testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
)
+type autoDep struct {
+ variation string
+ depTag dependencyTag
+}
+
+var (
+ rlibAutoDep = autoDep{variation: "rlib", depTag: rlibDepTag}
+ dylibAutoDep = autoDep{variation: "dylib", depTag: dylibDepTag}
+)
+
+type autoDeppable interface {
+ autoDep() autoDep
+}
+
func (mod *Module) begin(ctx BaseModuleContext) {
if mod.coverage != nil {
mod.coverage.begin(ctx)
@@ -679,19 +745,15 @@
}
//Append the dependencies exportedDirs
- if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
- depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
+ if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok {
+ depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...)
depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
}
- // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
- // This can be probably be refactored by defining a common exporter interface similar to cc's
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
linkDir := linkPathFromFilePath(linkFile.Path())
- if lib, ok := mod.compiler.(*libraryDecorator); ok {
- lib.linkDirs = append(lib.linkDirs, linkDir)
- } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
- procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
+ if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
+ lib.exportLinkDirs(linkDir)
}
}
@@ -742,14 +804,10 @@
}
// Make sure these dependencies are propagated
- if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
- lib.linkDirs = append(lib.linkDirs, linkPath)
- lib.depFlags = append(lib.depFlags, depFlag)
- } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
- procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
- procMacro.depFlags = append(procMacro.depFlags, depFlag)
+ if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
+ lib.exportLinkDirs(linkPath)
+ lib.exportDepFlags(depFlag)
}
-
}
})
@@ -811,11 +869,7 @@
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
deps := mod.deps(ctx)
commonDepVariations := []blueprint.Variation{}
@@ -838,6 +892,15 @@
{Mutator: "link", Variation: ""}}...),
dylibDepTag, deps.Dylibs...)
+ if deps.Rustlibs != nil {
+ autoDep := mod.compiler.(autoDeppable).autoDep()
+ actx.AddVariationDependencies(
+ append(commonDepVariations, []blueprint.Variation{
+ {Mutator: "rust_libraries", Variation: autoDep.variation},
+ {Mutator: "link", Variation: ""}}...),
+ autoDep.depTag, deps.Rustlibs...)
+ }
+
actx.AddVariationDependencies(append(commonDepVariations,
blueprint.Variation{Mutator: "link", Variation: "shared"}),
cc.SharedDepTag, deps.SharedLibs...)
@@ -862,19 +925,10 @@
}
}
-type baseModuleContext struct {
- android.BaseModuleContext
- moduleContextImpl
-}
-
func (mod *Module) beginMutator(actx android.BottomUpMutatorContext) {
ctx := &baseModuleContext{
BaseModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
mod.begin(ctx)
}
@@ -889,6 +943,18 @@
return name
}
+var _ android.HostToolProvider = (*Module)(nil)
+
+func (mod *Module) HostToolPath() android.OptionalPath {
+ if !mod.Host() {
+ return android.OptionalPath{}
+ }
+ if _, ok := mod.compiler.(*binaryDecorator); ok {
+ return mod.outputFile
+ }
+ return android.OptionalPath{}
+}
+
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 280c22a..08bc8ca 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -164,12 +164,12 @@
// Test to make sure dependencies are being picked up correctly.
func TestDepsTracking(t *testing.T) {
ctx := testRust(t, `
- rust_library_host_static {
+ rust_ffi_host_static {
name: "libstatic",
srcs: ["foo.rs"],
crate_name: "static",
}
- rust_library_host_shared {
+ rust_ffi_host_shared {
name: "libshared",
srcs: ["foo.rs"],
crate_name: "shared",
diff --git a/rust/test.go b/rust/test.go
index 416c557..e27a70c 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -105,6 +105,10 @@
return flags
}
+func (test *testDecorator) autoDep() autoDep {
+ return rlibAutoDep
+}
+
func init() {
// Rust tests are binary files built with --test.
android.RegisterModuleType("rust_test", RustTestFactory)
diff --git a/rust/testing.go b/rust/testing.go
index 4e186d3..3d583e1 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -21,14 +21,26 @@
func GatherRequiredDepsForTest() string {
bp := `
- rust_prebuilt_dylib {
+ rust_prebuilt_library {
name: "libstd_x86_64-unknown-linux-gnu",
- srcs: [""],
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd.so"],
+ },
host_supported: true,
}
- rust_prebuilt_dylib {
+ rust_prebuilt_library {
name: "libtest_x86_64-unknown-linux-gnu",
- srcs: [""],
+ crate_name: "test",
+ rlib: {
+ srcs: ["libtest.rlib"],
+ },
+ dylib: {
+ srcs: ["libtest.so"],
+ },
host_supported: true,
}
@@ -41,34 +53,21 @@
nocrt: true,
system_shared_libs: [],
}
- rust_library_dylib {
+ rust_library {
name: "libstd",
crate_name: "std",
srcs: ["foo.rs"],
no_stdlibs: true,
host_supported: true,
+ native_coverage: false,
}
- rust_library_rlib {
- name: "libstd.static",
- crate_name: "std",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- host_supported: true,
- }
- rust_library_dylib {
+ rust_library {
name: "libtest",
crate_name: "test",
srcs: ["foo.rs"],
no_stdlibs: true,
host_supported: true,
-
- }
- rust_library_rlib {
- name: "libtest.static",
- crate_name: "test",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- host_supported: true,
+ native_coverage: false,
}
` + cc.GatherRequiredDepsForTest(android.NoOsType)
@@ -83,17 +82,21 @@
ctx.RegisterModuleType("rust_test", RustTestFactory)
ctx.RegisterModuleType("rust_test_host", RustTestHostFactory)
ctx.RegisterModuleType("rust_library", RustLibraryFactory)
- ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
- ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
- ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
- ctx.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
ctx.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
- ctx.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
- ctx.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
- ctx.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
- ctx.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
+ ctx.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
+ ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
+ ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
+ ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
+ ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
+ ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
+ ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+ ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+ ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
// rust mutators
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
diff --git a/scripts/Android.bp b/scripts/Android.bp
index ac2f42f..7782c68 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -106,7 +106,7 @@
py3: {
enabled: false,
},
- }
+ },
}
python_binary_host {
@@ -192,5 +192,17 @@
python_binary_host {
name: "lint-project-xml",
main: "lint-project-xml.py",
- srcs: ["lint-project-xml.py"],
+ srcs: [
+ "lint-project-xml.py",
+ "ninja_rsp.py",
+ ],
+}
+
+python_binary_host {
+ name: "gen-kotlin-build-file.py",
+ main: "gen-kotlin-build-file.py",
+ srcs: [
+ "gen-kotlin-build-file.py",
+ "ninja_rsp.py",
+ ],
}
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index 9b68a82..1bc78e6 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -23,6 +23,15 @@
runtime-module-host-exports
i18n-module-test-exports
i18n-module-sdk
+ platform-mainline-sdk
+ platform-mainline-host-exports
+)
+
+# List of libraries installed on the platform that are needed for ART chroot
+# testing.
+PLATFORM_LIBRARIES=(
+ liblog
+ libartpalette-system
)
# We want to create apex modules for all supported architectures.
@@ -49,7 +58,8 @@
for product in "${PRODUCTS[@]}"; do
echo_and_run build/soong/soong_ui.bash --make-mode $@ \
TARGET_PRODUCT=${product} \
- ${MAINLINE_MODULES[@]}
+ ${MAINLINE_MODULES[@]} \
+ ${PLATFORM_LIBRARIES[@]}
PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
@@ -58,9 +68,11 @@
for module in "${MAINLINE_MODULES[@]}"; do
echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
done
+ for library in "${PLATFORM_LIBRARIES[@]}"; do
+ echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/lib/${library}.so ${DIST_DIR}/${TARGET_ARCH}/
+ done
done
-
# Create multi-archs SDKs in a different out directory. The multi-arch script
# uses Soong in --skip-make mode which cannot use the same directory as normal
# mode with make.
diff --git a/scripts/gen-kotlin-build-file.py b/scripts/gen-kotlin-build-file.py
new file mode 100644
index 0000000..83b4cd8
--- /dev/null
+++ b/scripts/gen-kotlin-build-file.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# 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.
+
+# Generates kotlinc module xml file to drive kotlinc
+
+import argparse
+import os
+
+from ninja_rsp import NinjaRspFileReader
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if arg.startswith('#'):
+ return
+ if not arg.strip():
+ continue
+ yield arg
+
+ parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+ parser.add_argument('--out', dest='out',
+ help='file to which the module.xml contents will be written.')
+ parser.add_argument('--classpath', dest='classpath', action='append', default=[],
+ help='classpath to pass to kotlinc.')
+ parser.add_argument('--name', dest='name',
+ help='name of the module.')
+ parser.add_argument('--out_dir', dest='out_dir',
+ help='directory to which kotlinc will write output files.')
+ parser.add_argument('--srcs', dest='srcs', action='append', default=[],
+ help='file containing whitespace separated list of source files.')
+ parser.add_argument('--common_srcs', dest='common_srcs', action='append', default=[],
+ help='file containing whitespace separated list of common multiplatform source files.')
+
+ return parser.parse_args()
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ if not args.out:
+ raise RuntimeError('--out argument is required')
+
+ if not args.name:
+ raise RuntimeError('--name argument is required')
+
+ with open(args.out, 'w') as f:
+ # Print preamble
+ f.write('<modules>\n')
+ f.write(' <module name="%s" type="java-production" outputDir="%s">\n' % (args.name, args.out_dir or ''))
+
+ # Print classpath entries
+ for c in args.classpath:
+ for entry in c.split(':'):
+ path = os.path.abspath(entry)
+ f.write(' <classpath path="%s"/>\n' % path)
+
+ # For each rsp file, print source entries
+ for rsp_file in args.srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ if src.endswith('.java'):
+ f.write(' <javaSourceRoots path="%s"/>\n' % path)
+ elif src.endswith('.kt'):
+ f.write(' <sources path="%s"/>\n' % path)
+ else:
+ raise RuntimeError('unknown source file type %s' % file)
+
+ for rsp_file in args.common_srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ f.write(' <sources path="%s"/>\n' % path)
+ f.write(' <commonSources path="%s"/>\n' % path)
+
+ f.write(' </module>\n')
+ f.write('</modules>\n')
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
deleted file mode 100755
index 177ca1b..0000000
--- a/scripts/gen-kotlin-build-file.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2018 Google Inc. All rights reserved.
-#
-# 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.
-
-# Generates kotlinc module xml file to standard output based on rsp files
-
-if [[ -z "$1" ]]; then
- echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
- exit 1
-fi
-
-# Classpath variable has a tendency to be prefixed by "-classpath", remove it.
-if [[ $1 == "-classpath" ]]; then
- shift
-fi;
-
-classpath=$1
-name=$2
-out_dir=$3
-shift 3
-
-# Path in the build file may be relative to the build file, we need to make them
-# absolute
-prefix="$(pwd)"
-
-get_abs_path () {
- local file="$1"
- if [[ "${file:0:1}" == '/' ]] ; then
- echo "${file}"
- else
- echo "${prefix}/${file}"
- fi
-}
-
-# Print preamble
-echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
-
-# Print classpath entries
-for file in $(echo "$classpath" | tr ":" "\n"); do
- path="$(get_abs_path "$file")"
- echo " <classpath path=\"${path}\"/>"
-done
-
-# For each rsp file, print source entries
-while (( "$#" )); do
- for file in $(cat "$1"); do
- path="$(get_abs_path "$file")"
- if [[ $file == *.java ]]; then
- echo " <javaSourceRoots path=\"${path}\"/>"
- elif [[ $file == *.kt ]]; then
- echo " <sources path=\"${path}\"/>"
- else
- echo "Unknown source file type ${file}"
- exit 1
- fi
- done
-
- shift
-done
-
-echo "</module></modules>"
diff --git a/scripts/lint-project-xml.py b/scripts/lint-project-xml.py
index 38c57ca..f1ef85d 100755
--- a/scripts/lint-project-xml.py
+++ b/scripts/lint-project-xml.py
@@ -19,6 +19,8 @@
import argparse
+from ninja_rsp import NinjaRspFileReader
+
def check_action(check_type):
"""
@@ -91,74 +93,6 @@
return parser.parse_args()
-class NinjaRspFileReader:
- """
- Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
- non-standard character by surrounding the whole entry with single quotes, and then replacing
- any single quotes in the entry with the escape sequence '\''.
- """
-
- def __init__(self, filename):
- self.f = open(filename, 'r')
- self.r = self.character_reader(self.f)
-
- def __iter__(self):
- return self
-
- def character_reader(self, f):
- """Turns a file into a generator that returns one character at a time."""
- while True:
- c = f.read(1)
- if c:
- yield c
- else:
- return
-
- def __next__(self):
- entry = self.read_entry()
- if entry:
- return entry
- else:
- raise StopIteration
-
- def read_entry(self):
- c = next(self.r, "")
- if not c:
- return ""
- elif c == "'":
- return self.read_quoted_entry()
- else:
- entry = c
- for c in self.r:
- if c == " " or c == "\n":
- break
- entry += c
- return entry
-
- def read_quoted_entry(self):
- entry = ""
- for c in self.r:
- if c == "'":
- # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
- # character to find out.
- c = next(self.r)
- if not c or c == " " or c == "\n":
- # End of the item
- return entry
- elif c == "\\":
- # Escape sequence, expect a '
- c = next(self.r)
- if c != "'":
- # Malformed escape sequence
- raise "malformed escape sequence %s'\\%s" % (entry, c)
- entry += "'"
- else:
- raise "malformed escape sequence %s'%s" % (entry, c)
- else:
- entry += c
- raise "unterminated quoted entry %s" % entry
-
-
def write_project_xml(f, args):
test_attr = "test='true' " if args.test else ""
diff --git a/scripts/ninja_rsp.py b/scripts/ninja_rsp.py
new file mode 100644
index 0000000..004ce47
--- /dev/null
+++ b/scripts/ninja_rsp.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2020 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.
+#
+
+"""This file reads entries from a Ninja rsp file."""
+
+class NinjaRspFileReader:
+ """
+ Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
+ non-standard character by surrounding the whole entry with single quotes, and then replacing
+ any single quotes in the entry with the escape sequence '\''.
+ """
+
+ def __init__(self, filename):
+ self.f = open(filename, 'r')
+ self.r = self.character_reader(self.f)
+
+ def __iter__(self):
+ return self
+
+ def character_reader(self, f):
+ """Turns a file into a generator that returns one character at a time."""
+ while True:
+ c = f.read(1)
+ if c:
+ yield c
+ else:
+ return
+
+ def __next__(self):
+ entry = self.read_entry()
+ if entry:
+ return entry
+ else:
+ raise StopIteration
+
+ def read_entry(self):
+ c = next(self.r, "")
+ if not c:
+ return ""
+ elif c == "'":
+ return self.read_quoted_entry()
+ else:
+ entry = c
+ for c in self.r:
+ if c == " " or c == "\n":
+ break
+ entry += c
+ return entry
+
+ def read_quoted_entry(self):
+ entry = ""
+ for c in self.r:
+ if c == "'":
+ # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
+ # character to find out.
+ c = next(self.r)
+ if not c or c == " " or c == "\n":
+ # End of the item
+ return entry
+ elif c == "\\":
+ # Escape sequence, expect a '
+ c = next(self.r)
+ if c != "'":
+ # Malformed escape sequence
+ raise "malformed escape sequence %s'\\%s" % (entry, c)
+ entry += "'"
+ else:
+ raise "malformed escape sequence %s'%s" % (entry, c)
+ else:
+ entry += c
+ raise "unterminated quoted entry %s" % entry
diff --git a/zip/Android.bp b/zip/Android.bp
index 259e010..5081e91 100644
--- a/zip/Android.bp
+++ b/zip/Android.bp
@@ -27,7 +27,6 @@
"rate_limit.go",
],
testSrcs: [
- "zip_test.go",
+ "zip_test.go",
],
}
-