Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a49795d authored by Colin Cross's avatar Colin Cross
Browse files

Replace ctx.ExpandSources with android.PathsForModuleSrc

Move the logic from ctx.ExpandSources into android.PathsForModuleSrc
and ctx.ExpandSource into android.PathForModuleSrc, and deprecate
them.  When combined with the pathDepsMutator this will let all
properties that take source paths also take filegroups or genrule
outputs, as long as they are tagged with `android:"path"`.

Test: All soong tests
Change-Id: I01625e76b5da19240e9649bf26a014eeeafcab8f
parent 07e51619
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ func FileGroupFactory() Module {
}

func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
	fg.srcs = ctx.ExpandSources(fg.properties.Srcs, fg.properties.Exclude_srcs)
	fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)

	if fg.properties.Path != nil {
		fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
+8 −81
Original line number Diff line number Diff line
@@ -854,7 +854,7 @@ func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)

		if a.commonProperties.Notice != nil {
			// For filegroup-based notice file references.
			a.noticeFile = ctx.ExpandSource(*a.commonProperties.Notice, "notice")
			a.noticeFile = PathForModuleSrc(ctx, *a.commonProperties.Notice)
		}
	}

@@ -1419,91 +1419,18 @@ type SourceFileProducer interface {

// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
// be tagged with `android:"path" to support automatic source module dependency resolution.
//
// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
func (ctx *androidModuleContext) ExpandSources(srcFiles, excludes []string) Paths {
	prefix := PathForModuleSrc(ctx).String()

	var expandedExcludes []string
	if excludes != nil {
		expandedExcludes = make([]string, 0, len(excludes))
	}

	for _, e := range excludes {
		if m := SrcIsModule(e); m != "" {
			module := ctx.GetDirectDepWithTag(m, SourceDepTag)
			if module == nil {
				if ctx.Config().AllowMissingDependencies() {
					ctx.AddMissingDependencies([]string{m})
				} else {
					ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
				}
				continue
			}
			if srcProducer, ok := module.(SourceFileProducer); ok {
				expandedExcludes = append(expandedExcludes, srcProducer.Srcs().Strings()...)
			} else {
				ctx.ModuleErrorf("srcs dependency %q is not a source file producing module", m)
			}
		} else {
			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
		}
	}
	expandedSrcFiles := make(Paths, 0, len(srcFiles))
	for _, s := range srcFiles {
		if m := SrcIsModule(s); m != "" {
			module := ctx.GetDirectDepWithTag(m, SourceDepTag)
			if module == nil {
				if ctx.Config().AllowMissingDependencies() {
					ctx.AddMissingDependencies([]string{m})
				} else {
					ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
				}
				continue
			}
			if srcProducer, ok := module.(SourceFileProducer); ok {
				moduleSrcs := srcProducer.Srcs()
				for _, e := range expandedExcludes {
					for j, ms := range moduleSrcs {
						if ms.String() == e {
							moduleSrcs = append(moduleSrcs[:j], moduleSrcs[j+1:]...)
						}
					}
				}
				expandedSrcFiles = append(expandedSrcFiles, moduleSrcs...)
			} else {
				ctx.ModuleErrorf("srcs dependency %q is not a source file producing module", m)
			}
		} else if pathtools.IsGlob(s) {
			globbedSrcFiles := ctx.GlobFiles(filepath.Join(prefix, s), expandedExcludes)
			globbedSrcFiles = PathsWithModuleSrcSubDir(ctx, globbedSrcFiles, "")
			expandedSrcFiles = append(expandedSrcFiles, globbedSrcFiles...)
		} else {
			p := PathForModuleSrc(ctx, s)
			j := findStringInSlice(p.String(), expandedExcludes)
			if j == -1 {
				expandedSrcFiles = append(expandedSrcFiles, p)
			}
		}
	}
	return expandedSrcFiles
	return PathsForModuleSrcExcludes(ctx, srcFiles, excludes)
}

// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
// be tagged with `android:"path" to support automatic source module dependency resolution.
//
// Deprecated: use PathForModuleSrc instead.
func (ctx *androidModuleContext) ExpandSource(srcFile, prop string) Path {
	srcFiles := ctx.ExpandSources([]string{srcFile}, nil)
	if len(srcFiles) == 1 {
		return srcFiles[0]
	} else if len(srcFiles) == 0 {
		if ctx.Config().AllowMissingDependencies() {
			ctx.AddMissingDependencies([]string{srcFile})
		} else {
			ctx.PropertyErrorf(prop, "%s path %s does not exist", prop, srcFile)
		}
		return nil
	} else {
		ctx.PropertyErrorf(prop, "module providing %s must produce exactly one file", prop)
		return nil
	}
	return PathForModuleSrc(ctx, srcFile)
}

// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
@@ -1511,7 +1438,7 @@ func (ctx *androidModuleContext) ExpandSource(srcFile, prop string) Path {
// dependency resolution.
func (ctx *androidModuleContext) ExpandOptionalSource(srcFile *string, prop string) OptionalPath {
	if srcFile != nil {
		return OptionalPathForPath(ctx.ExpandSource(*srcFile, prop))
		return OptionalPathForPath(PathForModuleSrc(ctx, *srcFile))
	}
	return OptionalPath{}
}
+120 −12
Original line number Diff line number Diff line
@@ -220,11 +220,104 @@ func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
// PathsForModuleSrc returns Paths rooted from the module's local source
// directory
func PathsForModuleSrc(ctx ModuleContext, paths []string) Paths {
	ret := make(Paths, len(paths))
	for i, path := range paths {
		ret[i] = PathForModuleSrc(ctx, path)
	return PathsForModuleSrcExcludes(ctx, paths, nil)
}

func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Paths {
	prefix := pathForModuleSrc(ctx).String()

	var expandedExcludes []string
	if excludes != nil {
		expandedExcludes = make([]string, 0, len(excludes))
	}

	for _, e := range excludes {
		if m := SrcIsModule(e); m != "" {
			module := ctx.GetDirectDepWithTag(m, SourceDepTag)
			if module == nil {
				if ctx.Config().AllowMissingDependencies() {
					ctx.AddMissingDependencies([]string{m})
				} else {
					ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
				}
				continue
			}
			if srcProducer, ok := module.(SourceFileProducer); ok {
				expandedExcludes = append(expandedExcludes, srcProducer.Srcs().Strings()...)
			} else {
				ctx.ModuleErrorf("srcs dependency %q is not a source file producing module", m)
			}
		} else {
			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
		}
	}

	if paths == nil {
		return nil
	}

	expandedSrcFiles := make(Paths, 0, len(paths))
	for _, s := range paths {
		srcFiles, err := expandOneSrcPath(ctx, s, expandedExcludes)
		if depErr, ok := err.(missingDependencyError); ok {
			if ctx.Config().AllowMissingDependencies() {
				ctx.AddMissingDependencies(depErr.missingDeps)
			} else {
				ctx.ModuleErrorf(`%s, is the property annotated with android:"path"?`, depErr.Error())
			}
		} else if err != nil {
			reportPathError(ctx, err)
		}
		expandedSrcFiles = append(expandedSrcFiles, srcFiles...)
	}
	return expandedSrcFiles
}

type missingDependencyError struct {
	missingDeps []string
}

func (e missingDependencyError) Error() string {
	return "missing dependencies: " + strings.Join(e.missingDeps, ", ")
}

func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (Paths, error) {
	if m := SrcIsModule(s); m != "" {
		module := ctx.GetDirectDepWithTag(m, SourceDepTag)
		if module == nil {
			return nil, missingDependencyError{[]string{m}}
		}
		if srcProducer, ok := module.(SourceFileProducer); ok {
			moduleSrcs := srcProducer.Srcs()
			for _, e := range expandedExcludes {
				for j := 0; j < len(moduleSrcs); j++ {
					if moduleSrcs[j].String() == e {
						moduleSrcs = append(moduleSrcs[:j], moduleSrcs[j+1:]...)
						j--
					}
				}
			}
			return moduleSrcs, nil
		} else {
			return nil, fmt.Errorf("path dependency %q is not a source file producing module", m)
		}
	} else if pathtools.IsGlob(s) {
		paths := ctx.GlobFiles(pathForModuleSrc(ctx, s).String(), expandedExcludes)
		return PathsWithModuleSrcSubDir(ctx, paths, ""), nil
	} else {
		p := pathForModuleSrc(ctx, s)
		if exists, _, err := ctx.Fs().Exists(p.String()); err != nil {
			reportPathErrorf(ctx, "%s: %s", p, err.Error())
		} else if !exists {
			reportPathErrorf(ctx, "module source path %q does not exist", p)
		}

		j := findStringInSlice(p.String(), expandedExcludes)
		if j >= 0 {
			return nil, nil
		}
		return Paths{p}, nil
	}
	return ret
}

// pathsForModuleSrcFromFullPath returns Paths rooted from the module's local
@@ -750,15 +843,30 @@ var _ resPathProvider = SourcePath{}

// PathForModuleSrc returns a Path representing the paths... under the
// module's local source directory.
func PathForModuleSrc(ctx ModuleContext, paths ...string) Path {
	path := pathForModuleSrc(ctx, paths...)

	if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
		reportPathErrorf(ctx, "%s: %s", path, err.Error())
	} else if !exists {
		reportPathErrorf(ctx, "module source path %q does not exist", path)
func PathForModuleSrc(ctx ModuleContext, pathComponents ...string) Path {
	p, err := validatePath(pathComponents...)
	if err != nil {
		reportPathError(ctx, err)
	}
	return path
	paths, err := expandOneSrcPath(ctx, p, nil)
	if err != nil {
		if depErr, ok := err.(missingDependencyError); ok {
			if ctx.Config().AllowMissingDependencies() {
				ctx.AddMissingDependencies(depErr.missingDeps)
			} else {
				ctx.ModuleErrorf(`%s, is the property annotated with android:"path"?`, depErr.Error())
			}
		} else {
			reportPathError(ctx, err)
		}
		return nil
	} else if len(paths) == 0 {
		reportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
		return nil
	} else if len(paths) > 1 {
		reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
	}
	return paths[0]
}

func pathForModuleSrc(ctx ModuleContext, paths ...string) SourcePath {
+190 −50
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import (
	"testing"

	"github.com/google/blueprint/pathtools"
	"github.com/google/blueprint/proptools"
)

type strsTestCase struct {
@@ -706,39 +707,117 @@ func TestPathForSource(t *testing.T) {
	}
}

type expandSourcesTestModule struct {
type pathForModuleSrcTestModule struct {
	ModuleBase
	props struct {
		Srcs         []string `android:"path"`
		Exclude_srcs []string `android:"path"`

		Src *string `android:"path"`
	}

	srcs Paths
	src string
	rel string

	srcs []string
	rels []string

	missingDeps []string
}

func expandSourcesTestModuleFactory() Module {
	module := &expandSourcesTestModule{}
func pathForModuleSrcTestModuleFactory() Module {
	module := &pathForModuleSrcTestModule{}
	module.AddProperties(&module.props)
	InitAndroidModule(module)
	return module
}

func (p *expandSourcesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
	p.srcs = ctx.ExpandSources(p.props.Srcs, p.props.Exclude_srcs)
func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
	srcs := PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
	p.srcs = srcs.Strings()

	for _, src := range p.srcs {
	for _, src := range srcs {
		p.rels = append(p.rels, src.Rel())
	}

	if p.props.Src != nil {
		src := PathForModuleSrc(ctx, *p.props.Src)
		if src != nil {
			p.src = src.String()
			p.rel = src.Rel()
		}
	}

	p.missingDeps = ctx.GetMissingDependencies()
}

func TestExpandSources(t *testing.T) {
	tests := []struct {
type pathForModuleSrcTestCase struct {
	name string
	bp   string
	srcs []string
	rels []string
	}{
	src  string
	rel  string
}

func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			config := TestConfig(buildDir, nil)
			ctx := NewTestContext()

			ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
			ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))

			fgBp := `
				filegroup {
					name: "a",
					srcs: ["src/a"],
				}
			`

			mockFS := map[string][]byte{
				"fg/Android.bp":     []byte(fgBp),
				"foo/Android.bp":    []byte(test.bp),
				"fg/src/a":          nil,
				"foo/src/b":         nil,
				"foo/src/c":         nil,
				"foo/src/d":         nil,
				"foo/src/e/e":       nil,
				"foo/src_special/$": nil,
			}

			ctx.MockFileSystem(mockFS)

			ctx.Register()
			_, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
			FailIfErrored(t, errs)
			_, errs = ctx.PrepareBuildActions(config)
			FailIfErrored(t, errs)

			m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)

			if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
				t.Errorf("want srcs %q, got %q", w, g)
			}

			if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
				t.Errorf("want rels %q, got %q", w, g)
			}

			if g, w := m.src, test.src; g != w {
				t.Errorf("want src %q, got %q", w, g)
			}

			if g, w := m.rel, test.rel; g != w {
				t.Errorf("want rel %q, got %q", w, g)
			}
		})
	}
}

func TestPathsForModuleSrc(t *testing.T) {
	tests := []pathForModuleSrcTestCase{
		{
			name: "path",
			bp: `
@@ -794,57 +873,118 @@ func TestExpandSources(t *testing.T) {
		},
	}

	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(buildDir)

	testPathForModuleSrc(t, buildDir, tests)
}

func TestPathForModuleSrc(t *testing.T) {
	tests := []pathForModuleSrcTestCase{
		{
			name: "path",
			bp: `
			test {
				name: "foo",
				src: "src/b",
			}`,
			src: "foo/src/b",
			rel: "src/b",
		},
		{
			name: "glob",
			bp: `
			test {
				name: "foo",
				src: "src/e/*",
			}`,
			src: "foo/src/e/e",
			rel: "src/e/e",
		},
		{
			name: "filegroup",
			bp: `
			test {
				name: "foo",
				src: ":a",
			}`,
			src: "fg/src/a",
			rel: "src/a",
		},
		{
			name: "special characters glob",
			bp: `
			test {
				name: "foo",
				src: "src_special/*",
			}`,
			src: "foo/src_special/$",
			rel: "src_special/$",
		},
	}

	buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(buildDir)

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
	testPathForModuleSrc(t, buildDir, tests)
}

func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(buildDir)

	config := TestConfig(buildDir, nil)
	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)

	ctx := NewTestContext()
	ctx.SetAllowMissingDependencies(true)

			ctx.RegisterModuleType("test", ModuleFactoryAdaptor(expandSourcesTestModuleFactory))
			ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))

			fgBp := `
				filegroup {
					name: "a",
					srcs: ["src/a"],
	bp := `
		test {
			name: "foo",
			srcs: [":a"],
			exclude_srcs: [":b"],
			src: ":c",
		}
	`

	mockFS := map[string][]byte{
				"fg/Android.bp":     []byte(fgBp),
				"foo/Android.bp":    []byte(test.bp),
				"fg/src/a":          nil,
				"foo/src/b":         nil,
				"foo/src/c":         nil,
				"foo/src/d":         nil,
				"foo/src/e/e":       nil,
				"foo/src_special/$": nil,
		"Android.bp": []byte(bp),
	}

	ctx.MockFileSystem(mockFS)

	ctx.Register()
			_, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
	FailIfErrored(t, errs)
	_, errs = ctx.PrepareBuildActions(config)
	FailIfErrored(t, errs)

			m := ctx.ModuleForTests("foo", "").Module().(*expandSourcesTestModule)
	foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)

			if g, w := m.srcs.Strings(), test.srcs; !reflect.DeepEqual(g, w) {
				t.Errorf("want srcs %q, got %q", w, g)
	if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
		t.Errorf("want missing deps %q, got %q", w, g)
	}

			if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
				t.Errorf("want rels %q, got %q", w, g)
	if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
		t.Errorf("want srcs %q, got %q", w, g)
	}
		})

	if g, w := foo.src, ""; g != w {
		t.Errorf("want src %q, got %q", w, g)
	}

}

func ExampleOutputPath_ReplaceExtension() {
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {

	// Return the singleton source after expanding any filegroup in the
	// sources.
	return ctx.ExpandSource((*p.srcs)[0], "")
	return PathForModuleSrc(ctx, (*p.srcs)[0])
}

func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
Loading