Loading android/module.go +8 −13 Original line number Diff line number Diff line Loading @@ -2495,18 +2495,9 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet { return outputFilesFromProvider, err } // TODO: add error when outputFilesFromProvider and err are both nil after // OutputFileProducer and SourceFileProducer are deprecated. if outputFileProducer, ok := module.(OutputFileProducer); ok { paths, err := outputFileProducer.OutputFiles(tag) if err != nil { return nil, fmt.Errorf("failed to get output file from module %q at tag %q: %s", pathContextName(ctx, module), tag, err.Error()) } return paths, nil } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { if sourceFileProducer, ok := module.(SourceFileProducer); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag) } paths := sourceFileProducer.Srcs() return paths, nil Loading @@ -2525,7 +2516,12 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, var outputFiles OutputFilesInfo fromProperty := false if mctx, isMctx := ctx.(ModuleContext); isMctx { type OutputFilesProviderModuleContext interface { OtherModuleProviderContext Module() Module } if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx { if mctx.Module() != module { outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider) } else { Loading @@ -2539,7 +2535,6 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, // TODO: Add a check for skipped context if outputFiles.isEmpty() { // TODO: Add a check for param module not having OutputFilesProvider set return nil, OutputFilesProviderNotSet } Loading android/module_test.go +97 −39 Original line number Diff line number Diff line Loading @@ -935,31 +935,54 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { } } type fakeBlueprintModule struct{} type sourceProducerTestModule struct { ModuleBase props struct { // A represents the source file A string } } func (fakeBlueprintModule) Name() string { return "foo" } func sourceProducerTestModuleFactory() Module { module := &sourceProducerTestModule{} module.AddProperties(&module.props) InitAndroidModule(module) return module } func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {} type sourceProducerTestModule struct { fakeBlueprintModule source Path } func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) } func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } type outputFilesTestModule struct { ModuleBase props struct { // A represents the tag A string // B represents the output file for tag A B string } } type outputFileProducerTestModule struct { fakeBlueprintModule output map[string]Path error map[string]error func outputFilesTestModuleFactory() Module { module := &outputFilesTestModule{} module.AddProperties(&module.props) InitAndroidModule(module) return module } func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { return PathsIfNonNil(o.output[tag]), o.error[tag] func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { if o.props.A != "" || o.props.B != "" { ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A) } // This is to simulate the case that some module uses an object to set its // OutputFilesProvider, but the object itself is empty. ctx.SetOutputFiles(Paths{}, "missing") } type pathContextAddMissingDependenciesWrapper struct { PathContext OtherModuleProviderContext missingDeps []string } Loading @@ -970,52 +993,87 @@ func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module bluepr return module.Name() } func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil } func TestOutputFileForModule(t *testing.T) { testcases := []struct { name string module blueprint.Module bp string tag string env map[string]string config func(*config) expected string missingDeps []string env map[string]string config func(*config) }{ { name: "SourceFileProducer", module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, expected: "foo.txt", bp: `spt_module { name: "test_module", a: "spt.txt", } `, tag: "", expected: "spt.txt", }, { name: "OutputFileProducer", module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, expected: "foo.txt", name: "OutputFileProviderEmptyStringTag", bp: `oft_module { name: "test_module", a: "", b: "empty.txt", } `, tag: "", expected: "empty.txt", }, { name: "OutputFileProducer_tag", module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, name: "OutputFileProviderTag", bp: `oft_module { name: "test_module", a: "foo", b: "foo.txt", } `, tag: "foo", expected: "foo.txt", }, { name: "OutputFileProducer_AllowMissingDependencies", name: "OutputFileAllowMissingDependencies", bp: `oft_module { name: "test_module", } `, tag: "missing", expected: "missing_output_file/test_module", missingDeps: []string{"test_module"}, config: func(config *config) { config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) }, module: &outputFileProducerTestModule{}, missingDeps: []string{"foo"}, expected: "missing_output_file/foo", }, } for _, tt := range testcases { config := TestConfig(buildDir, tt.env, "", nil) t.Run(tt.name, func(t *testing.T) { result := GroupFixturePreparers( PrepareForTestWithDefaults, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory) ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory) }), FixtureWithRootAndroidBp(tt.bp), ).RunTest(t) config := TestConfig(buildDir, tt.env, tt.bp, nil) if tt.config != nil { tt.config(config.config) } ctx := &pathContextAddMissingDependenciesWrapper{ PathContext: PathContextForTesting(config), OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), } got := OutputFileForModule(ctx, tt.module, tt.tag) AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag) AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got) AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) }) } } Loading
android/module.go +8 −13 Original line number Diff line number Diff line Loading @@ -2495,18 +2495,9 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet { return outputFilesFromProvider, err } // TODO: add error when outputFilesFromProvider and err are both nil after // OutputFileProducer and SourceFileProducer are deprecated. if outputFileProducer, ok := module.(OutputFileProducer); ok { paths, err := outputFileProducer.OutputFiles(tag) if err != nil { return nil, fmt.Errorf("failed to get output file from module %q at tag %q: %s", pathContextName(ctx, module), tag, err.Error()) } return paths, nil } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { if sourceFileProducer, ok := module.(SourceFileProducer); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag) } paths := sourceFileProducer.Srcs() return paths, nil Loading @@ -2525,7 +2516,12 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, var outputFiles OutputFilesInfo fromProperty := false if mctx, isMctx := ctx.(ModuleContext); isMctx { type OutputFilesProviderModuleContext interface { OtherModuleProviderContext Module() Module } if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx { if mctx.Module() != module { outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider) } else { Loading @@ -2539,7 +2535,6 @@ func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, // TODO: Add a check for skipped context if outputFiles.isEmpty() { // TODO: Add a check for param module not having OutputFilesProvider set return nil, OutputFilesProviderNotSet } Loading
android/module_test.go +97 −39 Original line number Diff line number Diff line Loading @@ -935,31 +935,54 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { } } type fakeBlueprintModule struct{} type sourceProducerTestModule struct { ModuleBase props struct { // A represents the source file A string } } func (fakeBlueprintModule) Name() string { return "foo" } func sourceProducerTestModuleFactory() Module { module := &sourceProducerTestModule{} module.AddProperties(&module.props) InitAndroidModule(module) return module } func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {} type sourceProducerTestModule struct { fakeBlueprintModule source Path } func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) } func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } type outputFilesTestModule struct { ModuleBase props struct { // A represents the tag A string // B represents the output file for tag A B string } } type outputFileProducerTestModule struct { fakeBlueprintModule output map[string]Path error map[string]error func outputFilesTestModuleFactory() Module { module := &outputFilesTestModule{} module.AddProperties(&module.props) InitAndroidModule(module) return module } func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { return PathsIfNonNil(o.output[tag]), o.error[tag] func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { if o.props.A != "" || o.props.B != "" { ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A) } // This is to simulate the case that some module uses an object to set its // OutputFilesProvider, but the object itself is empty. ctx.SetOutputFiles(Paths{}, "missing") } type pathContextAddMissingDependenciesWrapper struct { PathContext OtherModuleProviderContext missingDeps []string } Loading @@ -970,52 +993,87 @@ func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module bluepr return module.Name() } func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil } func TestOutputFileForModule(t *testing.T) { testcases := []struct { name string module blueprint.Module bp string tag string env map[string]string config func(*config) expected string missingDeps []string env map[string]string config func(*config) }{ { name: "SourceFileProducer", module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, expected: "foo.txt", bp: `spt_module { name: "test_module", a: "spt.txt", } `, tag: "", expected: "spt.txt", }, { name: "OutputFileProducer", module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, expected: "foo.txt", name: "OutputFileProviderEmptyStringTag", bp: `oft_module { name: "test_module", a: "", b: "empty.txt", } `, tag: "", expected: "empty.txt", }, { name: "OutputFileProducer_tag", module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, name: "OutputFileProviderTag", bp: `oft_module { name: "test_module", a: "foo", b: "foo.txt", } `, tag: "foo", expected: "foo.txt", }, { name: "OutputFileProducer_AllowMissingDependencies", name: "OutputFileAllowMissingDependencies", bp: `oft_module { name: "test_module", } `, tag: "missing", expected: "missing_output_file/test_module", missingDeps: []string{"test_module"}, config: func(config *config) { config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) }, module: &outputFileProducerTestModule{}, missingDeps: []string{"foo"}, expected: "missing_output_file/foo", }, } for _, tt := range testcases { config := TestConfig(buildDir, tt.env, "", nil) t.Run(tt.name, func(t *testing.T) { result := GroupFixturePreparers( PrepareForTestWithDefaults, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory) ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory) }), FixtureWithRootAndroidBp(tt.bp), ).RunTest(t) config := TestConfig(buildDir, tt.env, tt.bp, nil) if tt.config != nil { tt.config(config.config) } ctx := &pathContextAddMissingDependenciesWrapper{ PathContext: PathContextForTesting(config), OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), } got := OutputFileForModule(ctx, tt.module, tt.tag) AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag) AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got) AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) }) } }