• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18	"fmt"
19	"io/ioutil"
20	"os"
21	"path/filepath"
22	"reflect"
23	"regexp"
24	"sort"
25	"strings"
26
27	"github.com/google/blueprint"
28	"github.com/google/blueprint/bootstrap"
29	"github.com/google/blueprint/pathtools"
30)
31
32var absSrcDir string
33
34// PathContext is the subset of a (Module|Singleton)Context required by the
35// Path methods.
36type PathContext interface {
37	Config() Config
38	AddNinjaFileDeps(deps ...string)
39}
40
41type PathGlobContext interface {
42	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
43}
44
45var _ PathContext = SingletonContext(nil)
46var _ PathContext = ModuleContext(nil)
47
48// "Null" path context is a minimal path context for a given config.
49type NullPathContext struct {
50	config Config
51}
52
53func (NullPathContext) AddNinjaFileDeps(...string) {}
54func (ctx NullPathContext) Config() Config         { return ctx.config }
55
56// EarlyModulePathContext is a subset of EarlyModuleContext methods required by the
57// Path methods. These path methods can be called before any mutators have run.
58type EarlyModulePathContext interface {
59	PathContext
60	PathGlobContext
61
62	ModuleDir() string
63	ModuleErrorf(fmt string, args ...interface{})
64}
65
66var _ EarlyModulePathContext = ModuleContext(nil)
67
68// Glob globs files and directories matching globPattern relative to ModuleDir(),
69// paths in the excludes parameter will be omitted.
70func Glob(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
71	ret, err := ctx.GlobWithDeps(globPattern, excludes)
72	if err != nil {
73		ctx.ModuleErrorf("glob: %s", err.Error())
74	}
75	return pathsForModuleSrcFromFullPath(ctx, ret, true)
76}
77
78// GlobFiles globs *only* files (not directories) matching globPattern relative to ModuleDir().
79// Paths in the excludes parameter will be omitted.
80func GlobFiles(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
81	ret, err := ctx.GlobWithDeps(globPattern, excludes)
82	if err != nil {
83		ctx.ModuleErrorf("glob: %s", err.Error())
84	}
85	return pathsForModuleSrcFromFullPath(ctx, ret, false)
86}
87
88// ModuleWithDepsPathContext is a subset of *ModuleContext methods required by
89// the Path methods that rely on module dependencies having been resolved.
90type ModuleWithDepsPathContext interface {
91	EarlyModulePathContext
92	VisitDirectDepsBlueprint(visit func(blueprint.Module))
93	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
94}
95
96// ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
97// the Path methods that rely on module dependencies having been resolved and ability to report
98// missing dependency errors.
99type ModuleMissingDepsPathContext interface {
100	ModuleWithDepsPathContext
101	AddMissingDependencies(missingDeps []string)
102}
103
104type ModuleInstallPathContext interface {
105	BaseModuleContext
106
107	InstallInData() bool
108	InstallInTestcases() bool
109	InstallInSanitizerDir() bool
110	InstallInRamdisk() bool
111	InstallInVendorRamdisk() bool
112	InstallInDebugRamdisk() bool
113	InstallInRecovery() bool
114	InstallInRoot() bool
115	InstallForceOS() (*OsType, *ArchType)
116}
117
118var _ ModuleInstallPathContext = ModuleContext(nil)
119
120// errorfContext is the interface containing the Errorf method matching the
121// Errorf method in blueprint.SingletonContext.
122type errorfContext interface {
123	Errorf(format string, args ...interface{})
124}
125
126var _ errorfContext = blueprint.SingletonContext(nil)
127
128// moduleErrorf is the interface containing the ModuleErrorf method matching
129// the ModuleErrorf method in blueprint.ModuleContext.
130type moduleErrorf interface {
131	ModuleErrorf(format string, args ...interface{})
132}
133
134var _ moduleErrorf = blueprint.ModuleContext(nil)
135
136// reportPathError will register an error with the attached context. It
137// attempts ctx.ModuleErrorf for a better error message first, then falls
138// back to ctx.Errorf.
139func reportPathError(ctx PathContext, err error) {
140	ReportPathErrorf(ctx, "%s", err.Error())
141}
142
143// ReportPathErrorf will register an error with the attached context. It
144// attempts ctx.ModuleErrorf for a better error message first, then falls
145// back to ctx.Errorf.
146func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
147	if mctx, ok := ctx.(moduleErrorf); ok {
148		mctx.ModuleErrorf(format, args...)
149	} else if ectx, ok := ctx.(errorfContext); ok {
150		ectx.Errorf(format, args...)
151	} else {
152		panic(fmt.Sprintf(format, args...))
153	}
154}
155
156func pathContextName(ctx PathContext, module blueprint.Module) string {
157	if x, ok := ctx.(interface{ ModuleName(blueprint.Module) string }); ok {
158		return x.ModuleName(module)
159	} else if x, ok := ctx.(interface{ OtherModuleName(blueprint.Module) string }); ok {
160		return x.OtherModuleName(module)
161	}
162	return "unknown"
163}
164
165type Path interface {
166	// Returns the path in string form
167	String() string
168
169	// Ext returns the extension of the last element of the path
170	Ext() string
171
172	// Base returns the last element of the path
173	Base() string
174
175	// Rel returns the portion of the path relative to the directory it was created from.  For
176	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
177	// directory, and OutputPath.Join("foo").Rel() would return "foo".
178	Rel() string
179
180	// RelativeToTop returns a new path relative to the top, it is provided solely for use in tests.
181	//
182	// It is guaranteed to always return the same type as it is called on, e.g. if called on an
183	// InstallPath then the returned value can be converted to an InstallPath.
184	//
185	// A standard build has the following structure:
186	//   ../top/
187	//          out/ - make install files go here.
188	//          out/soong - this is the soongOutDir passed to NewTestConfig()
189	//          ... - the source files
190	//
191	// This function converts a path so that it appears relative to the ../top/ directory, i.e.
192	// * Make install paths, which have the pattern "soongOutDir/../<path>" are converted into the top
193	//   relative path "out/<path>"
194	// * Soong install paths and other writable paths, which have the pattern "soongOutDir/<path>" are
195	//   converted into the top relative path "out/soong/<path>".
196	// * Source paths are already relative to the top.
197	// * Phony paths are not relative to anything.
198	// * toolDepPath have an absolute but known value in so don't need making relative to anything in
199	//   order to test.
200	RelativeToTop() Path
201}
202
203const (
204	OutDir      = "out"
205	OutSoongDir = OutDir + "/soong"
206)
207
208// WritablePath is a type of path that can be used as an output for build rules.
209type WritablePath interface {
210	Path
211
212	// return the path to the build directory.
213	getSoongOutDir() string
214
215	// the writablePath method doesn't directly do anything,
216	// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
217	writablePath()
218
219	ReplaceExtension(ctx PathContext, ext string) OutputPath
220}
221
222type genPathProvider interface {
223	genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath
224}
225type objPathProvider interface {
226	objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath
227}
228type resPathProvider interface {
229	resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath
230}
231
232// GenPathWithExt derives a new file path in ctx's generated sources directory
233// from the current path, but with the new extension.
234func GenPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleGenPath {
235	if path, ok := p.(genPathProvider); ok {
236		return path.genPathWithExt(ctx, subdir, ext)
237	}
238	ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
239	return PathForModuleGen(ctx)
240}
241
242// ObjPathWithExt derives a new file path in ctx's object directory from the
243// current path, but with the new extension.
244func ObjPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleObjPath {
245	if path, ok := p.(objPathProvider); ok {
246		return path.objPathWithExt(ctx, subdir, ext)
247	}
248	ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
249	return PathForModuleObj(ctx)
250}
251
252// ResPathWithName derives a new path in ctx's output resource directory, using
253// the current path to create the directory name, and the `name` argument for
254// the filename.
255func ResPathWithName(ctx ModuleOutPathContext, p Path, name string) ModuleResPath {
256	if path, ok := p.(resPathProvider); ok {
257		return path.resPathWithName(ctx, name)
258	}
259	ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
260	return PathForModuleRes(ctx)
261}
262
263// OptionalPath is a container that may or may not contain a valid Path.
264type OptionalPath struct {
265	path          Path   // nil if invalid.
266	invalidReason string // Not applicable if path != nil. "" if the reason is unknown.
267}
268
269// OptionalPathForPath returns an OptionalPath containing the path.
270func OptionalPathForPath(path Path) OptionalPath {
271	return OptionalPath{path: path}
272}
273
274// InvalidOptionalPath returns an OptionalPath that is invalid with the given reason.
275func InvalidOptionalPath(reason string) OptionalPath {
276
277	return OptionalPath{invalidReason: reason}
278}
279
280// Valid returns whether there is a valid path
281func (p OptionalPath) Valid() bool {
282	return p.path != nil
283}
284
285// Path returns the Path embedded in this OptionalPath. You must be sure that
286// there is a valid path, since this method will panic if there is not.
287func (p OptionalPath) Path() Path {
288	if p.path == nil {
289		msg := "Requesting an invalid path"
290		if p.invalidReason != "" {
291			msg += ": " + p.invalidReason
292		}
293		panic(msg)
294	}
295	return p.path
296}
297
298// InvalidReason returns the reason that the optional path is invalid, or "" if it is valid.
299func (p OptionalPath) InvalidReason() string {
300	if p.path != nil {
301		return ""
302	}
303	if p.invalidReason == "" {
304		return "unknown"
305	}
306	return p.invalidReason
307}
308
309// AsPaths converts the OptionalPath into Paths.
310//
311// It returns nil if this is not valid, or a single length slice containing the Path embedded in
312// this OptionalPath.
313func (p OptionalPath) AsPaths() Paths {
314	if p.path == nil {
315		return nil
316	}
317	return Paths{p.path}
318}
319
320// RelativeToTop returns an OptionalPath with the path that was embedded having been replaced by the
321// result of calling Path.RelativeToTop on it.
322func (p OptionalPath) RelativeToTop() OptionalPath {
323	if p.path == nil {
324		return p
325	}
326	p.path = p.path.RelativeToTop()
327	return p
328}
329
330// String returns the string version of the Path, or "" if it isn't valid.
331func (p OptionalPath) String() string {
332	if p.path != nil {
333		return p.path.String()
334	} else {
335		return ""
336	}
337}
338
339// Paths is a slice of Path objects, with helpers to operate on the collection.
340type Paths []Path
341
342// RelativeToTop creates a new Paths containing the result of calling Path.RelativeToTop on each
343// item in this slice.
344func (p Paths) RelativeToTop() Paths {
345	ensureTestOnly()
346	if p == nil {
347		return p
348	}
349	ret := make(Paths, len(p))
350	for i, path := range p {
351		ret[i] = path.RelativeToTop()
352	}
353	return ret
354}
355
356func (paths Paths) containsPath(path Path) bool {
357	for _, p := range paths {
358		if p == path {
359			return true
360		}
361	}
362	return false
363}
364
365// PathsForSource returns Paths rooted from SrcDir, *not* rooted from the module's local source
366// directory
367func PathsForSource(ctx PathContext, paths []string) Paths {
368	ret := make(Paths, len(paths))
369	for i, path := range paths {
370		ret[i] = PathForSource(ctx, path)
371	}
372	return ret
373}
374
375// ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
376// module's local source directory, that are found in the tree. If any are not found, they are
377// omitted from the list, and dependencies are added so that we're re-run when they are added.
378func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
379	ret := make(Paths, 0, len(paths))
380	for _, path := range paths {
381		p := ExistentPathForSource(ctx, path)
382		if p.Valid() {
383			ret = append(ret, p.Path())
384		}
385	}
386	return ret
387}
388
389// PathsForModuleSrc returns a Paths{} containing the resolved references in paths:
390// * filepath, relative to local module directory, resolves as a filepath relative to the local
391//   source directory
392// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
393//  source directory.
394// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
395//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
396//    filepath.
397// Properties passed as the paths argument must have been annotated with struct tag
398// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
399// path_deps mutator.
400// If a requested module is not found as a dependency:
401//   * if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
402//     missing dependencies
403//   * otherwise, a ModuleError is thrown.
404func PathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) Paths {
405	return PathsForModuleSrcExcludes(ctx, paths, nil)
406}
407
408type SourceInput struct {
409	Context      ModuleMissingDepsPathContext
410	Paths        []string
411	ExcludePaths []string
412	IncludeDirs  bool
413}
414
415// PathsForModuleSrcExcludes returns a Paths{} containing the resolved references in paths, minus
416// those listed in excludes. Elements of paths and excludes are resolved as:
417// * filepath, relative to local module directory, resolves as a filepath relative to the local
418//   source directory
419// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
420//  source directory. Not valid in excludes.
421// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
422//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
423//    filepath.
424// excluding the items (similarly resolved
425// Properties passed as the paths argument must have been annotated with struct tag
426// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
427// path_deps mutator.
428// If a requested module is not found as a dependency:
429//   * if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
430//     missing dependencies
431//   * otherwise, a ModuleError is thrown.
432func PathsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) Paths {
433	return PathsRelativeToModuleSourceDir(SourceInput{
434		Context:      ctx,
435		Paths:        paths,
436		ExcludePaths: excludes,
437		IncludeDirs:  true,
438	})
439}
440
441func PathsRelativeToModuleSourceDir(input SourceInput) Paths {
442	ret, missingDeps := PathsAndMissingDepsRelativeToModuleSourceDir(input)
443	if input.Context.Config().AllowMissingDependencies() {
444		input.Context.AddMissingDependencies(missingDeps)
445	} else {
446		for _, m := range missingDeps {
447			input.Context.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
448		}
449	}
450	return ret
451}
452
453// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
454type OutputPaths []OutputPath
455
456// Paths returns the OutputPaths as a Paths
457func (p OutputPaths) Paths() Paths {
458	if p == nil {
459		return nil
460	}
461	ret := make(Paths, len(p))
462	for i, path := range p {
463		ret[i] = path
464	}
465	return ret
466}
467
468// Strings returns the string forms of the writable paths.
469func (p OutputPaths) Strings() []string {
470	if p == nil {
471		return nil
472	}
473	ret := make([]string, len(p))
474	for i, path := range p {
475		ret[i] = path.String()
476	}
477	return ret
478}
479
480// PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module.
481func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path {
482	goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false)
483	rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath())
484	return goBinaryInstallDir.Join(ctx, rel)
485}
486
487// Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax.
488// If the dependency is not found, a missingErrorDependency is returned.
489// If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned.
490func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag string) (Paths, error) {
491	module := GetModuleFromPathDep(ctx, moduleName, tag)
492	if module == nil {
493		return nil, missingDependencyError{[]string{moduleName}}
494	}
495	if aModule, ok := module.(Module); ok && !aModule.Enabled() {
496		return nil, missingDependencyError{[]string{moduleName}}
497	}
498	if outProducer, ok := module.(OutputFileProducer); ok {
499		outputFiles, err := outProducer.OutputFiles(tag)
500		if err != nil {
501			return nil, fmt.Errorf("path dependency %q: %s", path, err)
502		}
503		return outputFiles, nil
504	} else if tag != "" {
505		return nil, fmt.Errorf("path dependency %q is not an output file producing module", path)
506	} else if goBinary, ok := module.(bootstrap.GoBinaryTool); ok {
507		goBinaryPath := PathForGoBinary(ctx, goBinary)
508		return Paths{goBinaryPath}, nil
509	} else if srcProducer, ok := module.(SourceFileProducer); ok {
510		return srcProducer.Srcs(), nil
511	} else {
512		return nil, fmt.Errorf("path dependency %q is not a source file producing module", path)
513	}
514}
515
516// GetModuleFromPathDep will return the module that was added as a dependency automatically for
517// properties tagged with `android:"path"` or manually using ExtractSourceDeps or
518// ExtractSourcesDeps.
519//
520// The moduleName and tag supplied to this should be the values returned from SrcIsModuleWithTag.
521// Or, if no tag is expected then the moduleName should be the value returned by  SrcIsModule and
522// the tag must be "".
523//
524// If tag is "" then the returned module will be the dependency that was added for ":moduleName".
525// Otherwise, it is the dependency that was added for ":moduleName{tag}".
526func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) blueprint.Module {
527	var found blueprint.Module
528	// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
529	// module name and the tag. Dependencies added automatically for properties tagged with
530	// `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
531	// dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
532	// it will always be the case that the dependencies will be identical, i.e. the same tag and same
533	// moduleName referring to the same dependency module.
534	//
535	// It does not matter whether the moduleName is a fully qualified name or if the module
536	// dependency is a prebuilt module. All that matters is the same information is supplied to
537	// create the tag here as was supplied to create the tag when the dependency was added so that
538	// this finds the matching dependency module.
539	expectedTag := sourceOrOutputDepTag(moduleName, tag)
540	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
541		depTag := ctx.OtherModuleDependencyTag(module)
542		if depTag == expectedTag {
543			found = module
544		}
545	})
546	return found
547}
548
549// PathsAndMissingDepsForModuleSrcExcludes returns a Paths{} containing the resolved references in
550// paths, minus those listed in excludes. Elements of paths and excludes are resolved as:
551// * filepath, relative to local module directory, resolves as a filepath relative to the local
552//   source directory
553// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
554//  source directory. Not valid in excludes.
555// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
556//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
557//    filepath.
558// and a list of the module names of missing module dependencies are returned as the second return.
559// Properties passed as the paths argument must have been annotated with struct tag
560// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
561// path_deps mutator.
562func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) (Paths, []string) {
563	return PathsAndMissingDepsRelativeToModuleSourceDir(SourceInput{
564		Context:      ctx,
565		Paths:        paths,
566		ExcludePaths: excludes,
567		IncludeDirs:  true,
568	})
569}
570
571func PathsAndMissingDepsRelativeToModuleSourceDir(input SourceInput) (Paths, []string) {
572	prefix := pathForModuleSrc(input.Context).String()
573
574	var expandedExcludes []string
575	if input.ExcludePaths != nil {
576		expandedExcludes = make([]string, 0, len(input.ExcludePaths))
577	}
578
579	var missingExcludeDeps []string
580	for _, e := range input.ExcludePaths {
581		if m, t := SrcIsModuleWithTag(e); m != "" {
582			modulePaths, err := getPathsFromModuleDep(input.Context, e, m, t)
583			if m, ok := err.(missingDependencyError); ok {
584				missingExcludeDeps = append(missingExcludeDeps, m.missingDeps...)
585			} else if err != nil {
586				reportPathError(input.Context, err)
587			} else {
588				expandedExcludes = append(expandedExcludes, modulePaths.Strings()...)
589			}
590		} else {
591			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
592		}
593	}
594
595	if input.Paths == nil {
596		return nil, missingExcludeDeps
597	}
598
599	var missingDeps []string
600
601	expandedSrcFiles := make(Paths, 0, len(input.Paths))
602	for _, s := range input.Paths {
603		srcFiles, err := expandOneSrcPath(sourcePathInput{
604			context:          input.Context,
605			path:             s,
606			expandedExcludes: expandedExcludes,
607			includeDirs:      input.IncludeDirs,
608		})
609		if depErr, ok := err.(missingDependencyError); ok {
610			missingDeps = append(missingDeps, depErr.missingDeps...)
611		} else if err != nil {
612			reportPathError(input.Context, err)
613		}
614		expandedSrcFiles = append(expandedSrcFiles, srcFiles...)
615	}
616
617	return expandedSrcFiles, append(missingDeps, missingExcludeDeps...)
618}
619
620type missingDependencyError struct {
621	missingDeps []string
622}
623
624func (e missingDependencyError) Error() string {
625	return "missing dependencies: " + strings.Join(e.missingDeps, ", ")
626}
627
628type sourcePathInput struct {
629	context          ModuleWithDepsPathContext
630	path             string
631	expandedExcludes []string
632	includeDirs      bool
633}
634
635// Expands one path string to Paths rooted from the module's local source
636// directory, excluding those listed in the expandedExcludes.
637// Expands globs, references to SourceFileProducer or OutputFileProducer modules using the ":name" and ":name{.tag}" syntax.
638func expandOneSrcPath(input sourcePathInput) (Paths, error) {
639	excludePaths := func(paths Paths) Paths {
640		if len(input.expandedExcludes) == 0 {
641			return paths
642		}
643		remainder := make(Paths, 0, len(paths))
644		for _, p := range paths {
645			if !InList(p.String(), input.expandedExcludes) {
646				remainder = append(remainder, p)
647			}
648		}
649		return remainder
650	}
651	if m, t := SrcIsModuleWithTag(input.path); m != "" {
652		modulePaths, err := getPathsFromModuleDep(input.context, input.path, m, t)
653		if err != nil {
654			return nil, err
655		} else {
656			return excludePaths(modulePaths), nil
657		}
658	} else {
659		p := pathForModuleSrc(input.context, input.path)
660		if pathtools.IsGlob(input.path) {
661			paths := GlobFiles(input.context, p.String(), input.expandedExcludes)
662			return PathsWithModuleSrcSubDir(input.context, paths, ""), nil
663		} else {
664			if exists, _, err := input.context.Config().fs.Exists(p.String()); err != nil {
665				ReportPathErrorf(input.context, "%s: %s", p, err.Error())
666			} else if !exists && !input.context.Config().TestAllowNonExistentPaths {
667				ReportPathErrorf(input.context, "module source path %q does not exist", p)
668			} else if !input.includeDirs {
669				if isDir, err := input.context.Config().fs.IsDir(p.String()); exists && err != nil {
670					ReportPathErrorf(input.context, "%s: %s", p, err.Error())
671				} else if isDir {
672					ReportPathErrorf(input.context, "module source path %q is a directory", p)
673				}
674			}
675
676			if InList(p.String(), input.expandedExcludes) {
677				return nil, nil
678			}
679			return Paths{p}, nil
680		}
681	}
682}
683
684// pathsForModuleSrcFromFullPath returns Paths rooted from the module's local
685// source directory, but strip the local source directory from the beginning of
686// each string. If incDirs is false, strip paths with a trailing '/' from the list.
687// It intended for use in globs that only list files that exist, so it allows '$' in
688// filenames.
689func pathsForModuleSrcFromFullPath(ctx EarlyModulePathContext, paths []string, incDirs bool) Paths {
690	prefix := ctx.ModuleDir() + "/"
691	if prefix == "./" {
692		prefix = ""
693	}
694	ret := make(Paths, 0, len(paths))
695	for _, p := range paths {
696		if !incDirs && strings.HasSuffix(p, "/") {
697			continue
698		}
699		path := filepath.Clean(p)
700		if !strings.HasPrefix(path, prefix) {
701			ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
702			continue
703		}
704
705		srcPath, err := safePathForSource(ctx, ctx.ModuleDir(), path[len(prefix):])
706		if err != nil {
707			reportPathError(ctx, err)
708			continue
709		}
710
711		srcPath.basePath.rel = srcPath.path
712
713		ret = append(ret, srcPath)
714	}
715	return ret
716}
717
718// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's local source
719// directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
720func PathsWithOptionalDefaultForModuleSrc(ctx ModuleMissingDepsPathContext, input []string, def string) Paths {
721	if input != nil {
722		return PathsForModuleSrc(ctx, input)
723	}
724	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
725	// is created, we're run again.
726	path := filepath.Join(ctx.ModuleDir(), def)
727	return Glob(ctx, path, nil)
728}
729
730// Strings returns the Paths in string form
731func (p Paths) Strings() []string {
732	if p == nil {
733		return nil
734	}
735	ret := make([]string, len(p))
736	for i, path := range p {
737		ret[i] = path.String()
738	}
739	return ret
740}
741
742func CopyOfPaths(paths Paths) Paths {
743	return append(Paths(nil), paths...)
744}
745
746// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each.  It
747// modifies the Paths slice contents in place, and returns a subslice of the original slice.
748func FirstUniquePaths(list Paths) Paths {
749	// 128 was chosen based on BenchmarkFirstUniquePaths results.
750	if len(list) > 128 {
751		return firstUniquePathsMap(list)
752	}
753	return firstUniquePathsList(list)
754}
755
756// SortedUniquePaths returns all unique elements of a Paths in sorted order.  It modifies the
757// Paths slice contents in place, and returns a subslice of the original slice.
758func SortedUniquePaths(list Paths) Paths {
759	unique := FirstUniquePaths(list)
760	sort.Slice(unique, func(i, j int) bool {
761		return unique[i].String() < unique[j].String()
762	})
763	return unique
764}
765
766func firstUniquePathsList(list Paths) Paths {
767	k := 0
768outer:
769	for i := 0; i < len(list); i++ {
770		for j := 0; j < k; j++ {
771			if list[i] == list[j] {
772				continue outer
773			}
774		}
775		list[k] = list[i]
776		k++
777	}
778	return list[:k]
779}
780
781func firstUniquePathsMap(list Paths) Paths {
782	k := 0
783	seen := make(map[Path]bool, len(list))
784	for i := 0; i < len(list); i++ {
785		if seen[list[i]] {
786			continue
787		}
788		seen[list[i]] = true
789		list[k] = list[i]
790		k++
791	}
792	return list[:k]
793}
794
795// FirstUniqueInstallPaths returns all unique elements of an InstallPaths, keeping the first copy of each.  It
796// modifies the InstallPaths slice contents in place, and returns a subslice of the original slice.
797func FirstUniqueInstallPaths(list InstallPaths) InstallPaths {
798	// 128 was chosen based on BenchmarkFirstUniquePaths results.
799	if len(list) > 128 {
800		return firstUniqueInstallPathsMap(list)
801	}
802	return firstUniqueInstallPathsList(list)
803}
804
805func firstUniqueInstallPathsList(list InstallPaths) InstallPaths {
806	k := 0
807outer:
808	for i := 0; i < len(list); i++ {
809		for j := 0; j < k; j++ {
810			if list[i] == list[j] {
811				continue outer
812			}
813		}
814		list[k] = list[i]
815		k++
816	}
817	return list[:k]
818}
819
820func firstUniqueInstallPathsMap(list InstallPaths) InstallPaths {
821	k := 0
822	seen := make(map[InstallPath]bool, len(list))
823	for i := 0; i < len(list); i++ {
824		if seen[list[i]] {
825			continue
826		}
827		seen[list[i]] = true
828		list[k] = list[i]
829		k++
830	}
831	return list[:k]
832}
833
834// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each.  It
835// modifies the Paths slice contents in place, and returns a subslice of the original slice.
836func LastUniquePaths(list Paths) Paths {
837	totalSkip := 0
838	for i := len(list) - 1; i >= totalSkip; i-- {
839		skip := 0
840		for j := i - 1; j >= totalSkip; j-- {
841			if list[i] == list[j] {
842				skip++
843			} else {
844				list[j+skip] = list[j]
845			}
846		}
847		totalSkip += skip
848	}
849	return list[totalSkip:]
850}
851
852// ReversePaths returns a copy of a Paths in reverse order.
853func ReversePaths(list Paths) Paths {
854	if list == nil {
855		return nil
856	}
857	ret := make(Paths, len(list))
858	for i := range list {
859		ret[i] = list[len(list)-1-i]
860	}
861	return ret
862}
863
864func indexPathList(s Path, list []Path) int {
865	for i, l := range list {
866		if l == s {
867			return i
868		}
869	}
870
871	return -1
872}
873
874func inPathList(p Path, list []Path) bool {
875	return indexPathList(p, list) != -1
876}
877
878func FilterPathList(list []Path, filter []Path) (remainder []Path, filtered []Path) {
879	return FilterPathListPredicate(list, func(p Path) bool { return inPathList(p, filter) })
880}
881
882func FilterPathListPredicate(list []Path, predicate func(Path) bool) (remainder []Path, filtered []Path) {
883	for _, l := range list {
884		if predicate(l) {
885			filtered = append(filtered, l)
886		} else {
887			remainder = append(remainder, l)
888		}
889	}
890
891	return
892}
893
894// HasExt returns true of any of the paths have extension ext, otherwise false
895func (p Paths) HasExt(ext string) bool {
896	for _, path := range p {
897		if path.Ext() == ext {
898			return true
899		}
900	}
901
902	return false
903}
904
905// FilterByExt returns the subset of the paths that have extension ext
906func (p Paths) FilterByExt(ext string) Paths {
907	ret := make(Paths, 0, len(p))
908	for _, path := range p {
909		if path.Ext() == ext {
910			ret = append(ret, path)
911		}
912	}
913	return ret
914}
915
916// FilterOutByExt returns the subset of the paths that do not have extension ext
917func (p Paths) FilterOutByExt(ext string) Paths {
918	ret := make(Paths, 0, len(p))
919	for _, path := range p {
920		if path.Ext() != ext {
921			ret = append(ret, path)
922		}
923	}
924	return ret
925}
926
927// DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
928// (including subdirectories) are in a contiguous subslice of the list, and can be found in
929// O(log(N)) time using a binary search on the directory prefix.
930type DirectorySortedPaths Paths
931
932func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
933	ret := append(DirectorySortedPaths(nil), paths...)
934	sort.Slice(ret, func(i, j int) bool {
935		return ret[i].String() < ret[j].String()
936	})
937	return ret
938}
939
940// PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
941// that are in the specified directory and its subdirectories.
942func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
943	prefix := filepath.Clean(dir) + "/"
944	start := sort.Search(len(p), func(i int) bool {
945		return prefix < p[i].String()
946	})
947
948	ret := p[start:]
949
950	end := sort.Search(len(ret), func(i int) bool {
951		return !strings.HasPrefix(ret[i].String(), prefix)
952	})
953
954	ret = ret[:end]
955
956	return Paths(ret)
957}
958
959// WritablePaths is a slice of WritablePath, used for multiple outputs.
960type WritablePaths []WritablePath
961
962// RelativeToTop creates a new WritablePaths containing the result of calling Path.RelativeToTop on
963// each item in this slice.
964func (p WritablePaths) RelativeToTop() WritablePaths {
965	ensureTestOnly()
966	if p == nil {
967		return p
968	}
969	ret := make(WritablePaths, len(p))
970	for i, path := range p {
971		ret[i] = path.RelativeToTop().(WritablePath)
972	}
973	return ret
974}
975
976// Strings returns the string forms of the writable paths.
977func (p WritablePaths) Strings() []string {
978	if p == nil {
979		return nil
980	}
981	ret := make([]string, len(p))
982	for i, path := range p {
983		ret[i] = path.String()
984	}
985	return ret
986}
987
988// Paths returns the WritablePaths as a Paths
989func (p WritablePaths) Paths() Paths {
990	if p == nil {
991		return nil
992	}
993	ret := make(Paths, len(p))
994	for i, path := range p {
995		ret[i] = path
996	}
997	return ret
998}
999
1000type basePath struct {
1001	path string
1002	rel  string
1003}
1004
1005func (p basePath) Ext() string {
1006	return filepath.Ext(p.path)
1007}
1008
1009func (p basePath) Base() string {
1010	return filepath.Base(p.path)
1011}
1012
1013func (p basePath) Rel() string {
1014	if p.rel != "" {
1015		return p.rel
1016	}
1017	return p.path
1018}
1019
1020func (p basePath) String() string {
1021	return p.path
1022}
1023
1024func (p basePath) withRel(rel string) basePath {
1025	p.path = filepath.Join(p.path, rel)
1026	p.rel = rel
1027	return p
1028}
1029
1030// SourcePath is a Path representing a file path rooted from SrcDir
1031type SourcePath struct {
1032	basePath
1033
1034	// The sources root, i.e. Config.SrcDir()
1035	srcDir string
1036}
1037
1038func (p SourcePath) RelativeToTop() Path {
1039	ensureTestOnly()
1040	return p
1041}
1042
1043var _ Path = SourcePath{}
1044
1045func (p SourcePath) withRel(rel string) SourcePath {
1046	p.basePath = p.basePath.withRel(rel)
1047	return p
1048}
1049
1050// safePathForSource is for paths that we expect are safe -- only for use by go
1051// code that is embedding ninja variables in paths
1052func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
1053	p, err := validateSafePath(pathComponents...)
1054	ret := SourcePath{basePath{p, ""}, "."}
1055	if err != nil {
1056		return ret, err
1057	}
1058
1059	// absolute path already checked by validateSafePath
1060	if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) {
1061		return ret, fmt.Errorf("source path %q is in output", ret.String())
1062	}
1063
1064	return ret, err
1065}
1066
1067// pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
1068func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
1069	p, err := validatePath(pathComponents...)
1070	ret := SourcePath{basePath{p, ""}, "."}
1071	if err != nil {
1072		return ret, err
1073	}
1074
1075	// absolute path already checked by validatePath
1076	if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) {
1077		return ret, fmt.Errorf("source path %q is in output", ret.String())
1078	}
1079
1080	return ret, nil
1081}
1082
1083// existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
1084// path does not exist.
1085func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
1086	var files []string
1087
1088	if gctx, ok := ctx.(PathGlobContext); ok {
1089		// Use glob to produce proper dependencies, even though we only want
1090		// a single file.
1091		files, err = gctx.GlobWithDeps(path.String(), nil)
1092	} else {
1093		var result pathtools.GlobResult
1094		// We cannot add build statements in this context, so we fall back to
1095		// AddNinjaFileDeps
1096		result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
1097		ctx.AddNinjaFileDeps(result.Deps...)
1098		files = result.Matches
1099	}
1100
1101	if err != nil {
1102		return false, fmt.Errorf("glob: %s", err.Error())
1103	}
1104
1105	return len(files) > 0, nil
1106}
1107
1108// PathForSource joins the provided path components and validates that the result
1109// neither escapes the source dir nor is in the out dir.
1110// On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
1111func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
1112	path, err := pathForSource(ctx, pathComponents...)
1113	if err != nil {
1114		reportPathError(ctx, err)
1115	}
1116
1117	if pathtools.IsGlob(path.String()) {
1118		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
1119	}
1120
1121	if modCtx, ok := ctx.(ModuleMissingDepsPathContext); ok && ctx.Config().AllowMissingDependencies() {
1122		exists, err := existsWithDependencies(ctx, path)
1123		if err != nil {
1124			reportPathError(ctx, err)
1125		}
1126		if !exists {
1127			modCtx.AddMissingDependencies([]string{path.String()})
1128		}
1129	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
1130		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
1131	} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
1132		ReportPathErrorf(ctx, "source path %q does not exist", path)
1133	}
1134	return path
1135}
1136
1137// ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
1138// rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
1139// it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
1140// of the path changes.
1141func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
1142	path, err := pathForSource(ctx, pathComponents...)
1143	if err != nil {
1144		reportPathError(ctx, err)
1145		// No need to put the error message into the returned path since it has been reported already.
1146		return OptionalPath{}
1147	}
1148
1149	if pathtools.IsGlob(path.String()) {
1150		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
1151		return OptionalPath{}
1152	}
1153
1154	exists, err := existsWithDependencies(ctx, path)
1155	if err != nil {
1156		reportPathError(ctx, err)
1157		return OptionalPath{}
1158	}
1159	if !exists {
1160		return InvalidOptionalPath(path.String() + " does not exist")
1161	}
1162	return OptionalPathForPath(path)
1163}
1164
1165func (p SourcePath) String() string {
1166	return filepath.Join(p.srcDir, p.path)
1167}
1168
1169// Join creates a new SourcePath with paths... joined with the current path. The
1170// provided paths... may not use '..' to escape from the current path.
1171func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
1172	path, err := validatePath(paths...)
1173	if err != nil {
1174		reportPathError(ctx, err)
1175	}
1176	return p.withRel(path)
1177}
1178
1179// join is like Join but does less path validation.
1180func (p SourcePath) join(ctx PathContext, paths ...string) SourcePath {
1181	path, err := validateSafePath(paths...)
1182	if err != nil {
1183		reportPathError(ctx, err)
1184	}
1185	return p.withRel(path)
1186}
1187
1188// OverlayPath returns the overlay for `path' if it exists. This assumes that the
1189// SourcePath is the path to a resource overlay directory.
1190func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) OptionalPath {
1191	var relDir string
1192	if srcPath, ok := path.(SourcePath); ok {
1193		relDir = srcPath.path
1194	} else {
1195		ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
1196		// No need to put the error message into the returned path since it has been reported already.
1197		return OptionalPath{}
1198	}
1199	dir := filepath.Join(p.srcDir, p.path, relDir)
1200	// Use Glob so that we are run again if the directory is added.
1201	if pathtools.IsGlob(dir) {
1202		ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
1203	}
1204	paths, err := ctx.GlobWithDeps(dir, nil)
1205	if err != nil {
1206		ReportPathErrorf(ctx, "glob: %s", err.Error())
1207		return OptionalPath{}
1208	}
1209	if len(paths) == 0 {
1210		return InvalidOptionalPath(dir + " does not exist")
1211	}
1212	relPath := Rel(ctx, p.srcDir, paths[0])
1213	return OptionalPathForPath(PathForSource(ctx, relPath))
1214}
1215
1216// OutputPath is a Path representing an intermediates file path rooted from the build directory
1217type OutputPath struct {
1218	basePath
1219
1220	// The soong build directory, i.e. Config.SoongOutDir()
1221	soongOutDir string
1222
1223	fullPath string
1224}
1225
1226func (p OutputPath) withRel(rel string) OutputPath {
1227	p.basePath = p.basePath.withRel(rel)
1228	p.fullPath = filepath.Join(p.fullPath, rel)
1229	return p
1230}
1231
1232func (p OutputPath) WithoutRel() OutputPath {
1233	p.basePath.rel = filepath.Base(p.basePath.path)
1234	return p
1235}
1236
1237func (p OutputPath) getSoongOutDir() string {
1238	return p.soongOutDir
1239}
1240
1241func (p OutputPath) RelativeToTop() Path {
1242	return p.outputPathRelativeToTop()
1243}
1244
1245func (p OutputPath) outputPathRelativeToTop() OutputPath {
1246	p.fullPath = StringPathRelativeToTop(p.soongOutDir, p.fullPath)
1247	p.soongOutDir = OutSoongDir
1248	return p
1249}
1250
1251func (p OutputPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1252	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1253}
1254
1255var _ Path = OutputPath{}
1256var _ WritablePath = OutputPath{}
1257var _ objPathProvider = OutputPath{}
1258
1259// toolDepPath is a Path representing a dependency of the build tool.
1260type toolDepPath struct {
1261	basePath
1262}
1263
1264func (t toolDepPath) RelativeToTop() Path {
1265	ensureTestOnly()
1266	return t
1267}
1268
1269var _ Path = toolDepPath{}
1270
1271// pathForBuildToolDep returns a toolDepPath representing the given path string.
1272// There is no validation for the path, as it is "trusted": It may fail
1273// normal validation checks. For example, it may be an absolute path.
1274// Only use this function to construct paths for dependencies of the build
1275// tool invocation.
1276func pathForBuildToolDep(ctx PathContext, path string) toolDepPath {
1277	return toolDepPath{basePath{path, ""}}
1278}
1279
1280// PathForOutput joins the provided paths and returns an OutputPath that is
1281// validated to not escape the build dir.
1282// On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
1283func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
1284	path, err := validatePath(pathComponents...)
1285	if err != nil {
1286		reportPathError(ctx, err)
1287	}
1288	fullPath := filepath.Join(ctx.Config().soongOutDir, path)
1289	path = fullPath[len(fullPath)-len(path):]
1290	return OutputPath{basePath{path, ""}, ctx.Config().soongOutDir, fullPath}
1291}
1292
1293// PathsForOutput returns Paths rooted from soongOutDir
1294func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
1295	ret := make(WritablePaths, len(paths))
1296	for i, path := range paths {
1297		ret[i] = PathForOutput(ctx, path)
1298	}
1299	return ret
1300}
1301
1302func (p OutputPath) writablePath() {}
1303
1304func (p OutputPath) String() string {
1305	return p.fullPath
1306}
1307
1308// Join creates a new OutputPath with paths... joined with the current path. The
1309// provided paths... may not use '..' to escape from the current path.
1310func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
1311	path, err := validatePath(paths...)
1312	if err != nil {
1313		reportPathError(ctx, err)
1314	}
1315	return p.withRel(path)
1316}
1317
1318// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
1319func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
1320	if strings.Contains(ext, "/") {
1321		ReportPathErrorf(ctx, "extension %q cannot contain /", ext)
1322	}
1323	ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
1324	ret.rel = pathtools.ReplaceExtension(p.rel, ext)
1325	return ret
1326}
1327
1328// InSameDir creates a new OutputPath from the directory of the current OutputPath joined with the elements in paths.
1329func (p OutputPath) InSameDir(ctx PathContext, paths ...string) OutputPath {
1330	path, err := validatePath(paths...)
1331	if err != nil {
1332		reportPathError(ctx, err)
1333	}
1334
1335	ret := PathForOutput(ctx, filepath.Dir(p.path), path)
1336	ret.rel = filepath.Join(filepath.Dir(p.rel), path)
1337	return ret
1338}
1339
1340// PathForIntermediates returns an OutputPath representing the top-level
1341// intermediates directory.
1342func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
1343	path, err := validatePath(paths...)
1344	if err != nil {
1345		reportPathError(ctx, err)
1346	}
1347	return PathForOutput(ctx, ".intermediates", path)
1348}
1349
1350var _ genPathProvider = SourcePath{}
1351var _ objPathProvider = SourcePath{}
1352var _ resPathProvider = SourcePath{}
1353
1354// PathForModuleSrc returns a Path representing the paths... under the
1355// module's local source directory.
1356func PathForModuleSrc(ctx ModuleMissingDepsPathContext, pathComponents ...string) Path {
1357	// Just join the components textually just to make sure that it does not corrupt a fully qualified
1358	// module reference, e.g. if the pathComponents is "://other:foo" then using filepath.Join() or
1359	// validatePath() will corrupt it, e.g. replace "//" with "/". If the path is not a module
1360	// reference then it will be validated by expandOneSrcPath anyway when it calls expandOneSrcPath.
1361	p := strings.Join(pathComponents, string(filepath.Separator))
1362	paths, err := expandOneSrcPath(sourcePathInput{context: ctx, path: p, includeDirs: true})
1363	if err != nil {
1364		if depErr, ok := err.(missingDependencyError); ok {
1365			if ctx.Config().AllowMissingDependencies() {
1366				ctx.AddMissingDependencies(depErr.missingDeps)
1367			} else {
1368				ctx.ModuleErrorf(`%s, is the property annotated with android:"path"?`, depErr.Error())
1369			}
1370		} else {
1371			reportPathError(ctx, err)
1372		}
1373		return nil
1374	} else if len(paths) == 0 {
1375		ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
1376		return nil
1377	} else if len(paths) > 1 {
1378		ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
1379	}
1380	return paths[0]
1381}
1382
1383func pathForModuleSrc(ctx EarlyModulePathContext, paths ...string) SourcePath {
1384	p, err := validatePath(paths...)
1385	if err != nil {
1386		reportPathError(ctx, err)
1387	}
1388
1389	path, err := pathForSource(ctx, ctx.ModuleDir(), p)
1390	if err != nil {
1391		reportPathError(ctx, err)
1392	}
1393
1394	path.basePath.rel = p
1395
1396	return path
1397}
1398
1399// PathsWithModuleSrcSubDir takes a list of Paths and returns a new list of Paths where Rel() on each path
1400// will return the path relative to subDir in the module's source directory.  If any input paths are not located
1401// inside subDir then a path error will be reported.
1402func PathsWithModuleSrcSubDir(ctx EarlyModulePathContext, paths Paths, subDir string) Paths {
1403	paths = append(Paths(nil), paths...)
1404	subDirFullPath := pathForModuleSrc(ctx, subDir)
1405	for i, path := range paths {
1406		rel := Rel(ctx, subDirFullPath.String(), path.String())
1407		paths[i] = subDirFullPath.join(ctx, rel)
1408	}
1409	return paths
1410}
1411
1412// PathWithModuleSrcSubDir takes a Path and returns a Path where Rel() will return the path relative to subDir in the
1413// module's source directory.  If the input path is not located inside subDir then a path error will be reported.
1414func PathWithModuleSrcSubDir(ctx EarlyModulePathContext, path Path, subDir string) Path {
1415	subDirFullPath := pathForModuleSrc(ctx, subDir)
1416	rel := Rel(ctx, subDirFullPath.String(), path.String())
1417	return subDirFullPath.Join(ctx, rel)
1418}
1419
1420// OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
1421// valid path if p is non-nil.
1422func OptionalPathForModuleSrc(ctx ModuleMissingDepsPathContext, p *string) OptionalPath {
1423	if p == nil {
1424		return OptionalPath{}
1425	}
1426	return OptionalPathForPath(PathForModuleSrc(ctx, *p))
1427}
1428
1429func (p SourcePath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
1430	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1431}
1432
1433func (p SourcePath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1434	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1435}
1436
1437func (p SourcePath) resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath {
1438	// TODO: Use full directory if the new ctx is not the current ctx?
1439	return PathForModuleRes(ctx, p.path, name)
1440}
1441
1442// ModuleOutPath is a Path representing a module's output directory.
1443type ModuleOutPath struct {
1444	OutputPath
1445}
1446
1447func (p ModuleOutPath) RelativeToTop() Path {
1448	p.OutputPath = p.outputPathRelativeToTop()
1449	return p
1450}
1451
1452var _ Path = ModuleOutPath{}
1453var _ WritablePath = ModuleOutPath{}
1454
1455func (p ModuleOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1456	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1457}
1458
1459// ModuleOutPathContext Subset of ModuleContext functions necessary for output path methods.
1460type ModuleOutPathContext interface {
1461	PathContext
1462
1463	ModuleName() string
1464	ModuleDir() string
1465	ModuleSubDir() string
1466}
1467
1468func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
1469	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
1470}
1471
1472// PathForVndkRefAbiDump returns an OptionalPath representing the path of the
1473// reference abi dump for the given module. This is not guaranteed to be valid.
1474func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName string,
1475	isNdk, isLlndkOrVndk, isGzip bool) OptionalPath {
1476
1477	currentArchType := ctx.Arch().ArchType
1478	primaryArchType := ctx.Config().DevicePrimaryArchType()
1479	archName := currentArchType.String()
1480	if currentArchType != primaryArchType {
1481		archName += "_" + primaryArchType.String()
1482	}
1483
1484	var dirName string
1485	if isNdk {
1486		dirName = "ndk"
1487	} else if isLlndkOrVndk {
1488		dirName = "vndk"
1489	} else {
1490		dirName = "platform" // opt-in libs
1491	}
1492
1493	binderBitness := ctx.DeviceConfig().BinderBitness()
1494
1495	var ext string
1496	if isGzip {
1497		ext = ".lsdump.gz"
1498	} else {
1499		ext = ".lsdump"
1500	}
1501
1502	return ExistentPathForSource(ctx, "prebuilts", "abi-dumps", dirName,
1503		version, binderBitness, archName, "source-based",
1504		fileName+ext)
1505}
1506
1507// PathForModuleOut returns a Path representing the paths... under the module's
1508// output directory.
1509func PathForModuleOut(ctx ModuleOutPathContext, paths ...string) ModuleOutPath {
1510	p, err := validatePath(paths...)
1511	if err != nil {
1512		reportPathError(ctx, err)
1513	}
1514	return ModuleOutPath{
1515		OutputPath: pathForModuleOut(ctx).withRel(p),
1516	}
1517}
1518
1519// ModuleGenPath is a Path representing the 'gen' directory in a module's output
1520// directory. Mainly used for generated sources.
1521type ModuleGenPath struct {
1522	ModuleOutPath
1523}
1524
1525func (p ModuleGenPath) RelativeToTop() Path {
1526	p.OutputPath = p.outputPathRelativeToTop()
1527	return p
1528}
1529
1530var _ Path = ModuleGenPath{}
1531var _ WritablePath = ModuleGenPath{}
1532var _ genPathProvider = ModuleGenPath{}
1533var _ objPathProvider = ModuleGenPath{}
1534
1535// PathForModuleGen returns a Path representing the paths... under the module's
1536// `gen' directory.
1537func PathForModuleGen(ctx ModuleOutPathContext, paths ...string) ModuleGenPath {
1538	p, err := validatePath(paths...)
1539	if err != nil {
1540		reportPathError(ctx, err)
1541	}
1542	return ModuleGenPath{
1543		ModuleOutPath: ModuleOutPath{
1544			OutputPath: pathForModuleOut(ctx).withRel("gen").withRel(p),
1545		},
1546	}
1547}
1548
1549func (p ModuleGenPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
1550	// TODO: make a different path for local vs remote generated files?
1551	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1552}
1553
1554func (p ModuleGenPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1555	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1556}
1557
1558// ModuleObjPath is a Path representing the 'obj' directory in a module's output
1559// directory. Used for compiled objects.
1560type ModuleObjPath struct {
1561	ModuleOutPath
1562}
1563
1564func (p ModuleObjPath) RelativeToTop() Path {
1565	p.OutputPath = p.outputPathRelativeToTop()
1566	return p
1567}
1568
1569var _ Path = ModuleObjPath{}
1570var _ WritablePath = ModuleObjPath{}
1571
1572// PathForModuleObj returns a Path representing the paths... under the module's
1573// 'obj' directory.
1574func PathForModuleObj(ctx ModuleOutPathContext, pathComponents ...string) ModuleObjPath {
1575	p, err := validatePath(pathComponents...)
1576	if err != nil {
1577		reportPathError(ctx, err)
1578	}
1579	return ModuleObjPath{PathForModuleOut(ctx, "obj", p)}
1580}
1581
1582// ModuleResPath is a a Path representing the 'res' directory in a module's
1583// output directory.
1584type ModuleResPath struct {
1585	ModuleOutPath
1586}
1587
1588func (p ModuleResPath) RelativeToTop() Path {
1589	p.OutputPath = p.outputPathRelativeToTop()
1590	return p
1591}
1592
1593var _ Path = ModuleResPath{}
1594var _ WritablePath = ModuleResPath{}
1595
1596// PathForModuleRes returns a Path representing the paths... under the module's
1597// 'res' directory.
1598func PathForModuleRes(ctx ModuleOutPathContext, pathComponents ...string) ModuleResPath {
1599	p, err := validatePath(pathComponents...)
1600	if err != nil {
1601		reportPathError(ctx, err)
1602	}
1603
1604	return ModuleResPath{PathForModuleOut(ctx, "res", p)}
1605}
1606
1607// InstallPath is a Path representing a installed file path rooted from the build directory
1608type InstallPath struct {
1609	basePath
1610
1611	// The soong build directory, i.e. Config.SoongOutDir()
1612	soongOutDir string
1613
1614	// partitionDir is the part of the InstallPath that is automatically determined according to the context.
1615	// For example, it is host/<os>-<arch> for host modules, and target/product/<device>/<partition> for device modules.
1616	partitionDir string
1617
1618	partition string
1619
1620	// makePath indicates whether this path is for Soong (false) or Make (true).
1621	makePath bool
1622}
1623
1624// Will panic if called from outside a test environment.
1625func ensureTestOnly() {
1626	if PrefixInList(os.Args, "-test.") {
1627		return
1628	}
1629	panic(fmt.Errorf("Not in test. Command line:\n  %s", strings.Join(os.Args, "\n  ")))
1630}
1631
1632func (p InstallPath) RelativeToTop() Path {
1633	ensureTestOnly()
1634	p.soongOutDir = OutSoongDir
1635	return p
1636}
1637
1638func (p InstallPath) getSoongOutDir() string {
1639	return p.soongOutDir
1640}
1641
1642func (p InstallPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
1643	panic("Not implemented")
1644}
1645
1646var _ Path = InstallPath{}
1647var _ WritablePath = InstallPath{}
1648
1649func (p InstallPath) writablePath() {}
1650
1651func (p InstallPath) String() string {
1652	if p.makePath {
1653		// Make path starts with out/ instead of out/soong.
1654		return filepath.Join(p.soongOutDir, "../", p.path)
1655	} else {
1656		return filepath.Join(p.soongOutDir, p.path)
1657	}
1658}
1659
1660// PartitionDir returns the path to the partition where the install path is rooted at. It is
1661// out/soong/target/product/<device>/<partition> for device modules, and out/soong/host/<os>-<arch> for host modules.
1662// The ./soong is dropped if the install path is for Make.
1663func (p InstallPath) PartitionDir() string {
1664	if p.makePath {
1665		return filepath.Join(p.soongOutDir, "../", p.partitionDir)
1666	} else {
1667		return filepath.Join(p.soongOutDir, p.partitionDir)
1668	}
1669}
1670
1671// Join creates a new InstallPath with paths... joined with the current path. The
1672// provided paths... may not use '..' to escape from the current path.
1673func (p InstallPath) Join(ctx PathContext, paths ...string) InstallPath {
1674	path, err := validatePath(paths...)
1675	if err != nil {
1676		reportPathError(ctx, err)
1677	}
1678	return p.withRel(path)
1679}
1680
1681func (p InstallPath) withRel(rel string) InstallPath {
1682	p.basePath = p.basePath.withRel(rel)
1683	return p
1684}
1685
1686// Deprecated: ToMakePath is a noop, PathForModuleInstall always returns Make paths when building
1687// embedded in Make.
1688func (p InstallPath) ToMakePath() InstallPath {
1689	p.makePath = true
1690	return p
1691}
1692
1693// PathForModuleInstall returns a Path representing the install path for the
1694// module appended with paths...
1695func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
1696	os, arch := osAndArch(ctx)
1697	partition := modulePartition(ctx, os)
1698	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
1699}
1700
1701// PathForHostDexInstall returns an InstallPath representing the install path for the
1702// module appended with paths...
1703func PathForHostDexInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
1704	return makePathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", ctx.Debug(), pathComponents...)
1705}
1706
1707// PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
1708func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
1709	os, arch := osAndArch(ctx)
1710	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
1711}
1712
1713func osAndArch(ctx ModuleInstallPathContext) (OsType, ArchType) {
1714	os := ctx.Os()
1715	arch := ctx.Arch().ArchType
1716	forceOS, forceArch := ctx.InstallForceOS()
1717	if forceOS != nil {
1718		os = *forceOS
1719	}
1720	if forceArch != nil {
1721		arch = *forceArch
1722	}
1723	return os, arch
1724}
1725
1726func makePathForInstall(ctx ModuleInstallPathContext, os OsType, arch ArchType, partition string, debug bool, pathComponents ...string) InstallPath {
1727	ret := pathForInstall(ctx, os, arch, partition, debug, pathComponents...)
1728	return ret
1729}
1730
1731func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
1732	pathComponents ...string) InstallPath {
1733
1734	var partionPaths []string
1735
1736	if os.Class == Device {
1737		partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
1738	} else {
1739		osName := os.String()
1740		if os == Linux || os == LinuxMusl {
1741			// instead of linux_glibc
1742			osName = "linux"
1743		}
1744		// SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
1745		// and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
1746		// to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
1747		// Let's keep using x86 for the existing cases until we have a need to support
1748		// other architectures.
1749		archName := arch.String()
1750		if os.Class == Host && (arch == X86_64 || arch == Common) {
1751			archName = "x86"
1752		}
1753		partionPaths = []string{"host", osName + "-" + archName, partition}
1754	}
1755	if debug {
1756		partionPaths = append([]string{"debug"}, partionPaths...)
1757	}
1758
1759	partionPath, err := validatePath(partionPaths...)
1760	if err != nil {
1761		reportPathError(ctx, err)
1762	}
1763
1764	base := InstallPath{
1765		basePath:     basePath{partionPath, ""},
1766		soongOutDir:  ctx.Config().soongOutDir,
1767		partitionDir: partionPath,
1768		partition:    partition,
1769	}
1770
1771	if ctx.Config().KatiEnabled() {
1772		base.makePath = true
1773	}
1774
1775	return base.Join(ctx, pathComponents...)
1776}
1777
1778func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
1779	base := InstallPath{
1780		basePath:     basePath{prefix, ""},
1781		soongOutDir:  ctx.Config().soongOutDir,
1782		partitionDir: prefix,
1783		makePath:     false,
1784	}
1785	return base.Join(ctx, paths...)
1786}
1787
1788func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
1789	return pathForNdkOrSdkInstall(ctx, "ndk", paths)
1790}
1791
1792func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
1793	return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
1794}
1795
1796func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
1797	rel := Rel(ctx, strings.TrimSuffix(path.PartitionDir(), path.partition), path.String())
1798	return "/" + rel
1799}
1800
1801func modulePartition(ctx ModuleInstallPathContext, os OsType) string {
1802	var partition string
1803	if ctx.InstallInTestcases() {
1804		// "testcases" install directory can be used for host or device modules.
1805		partition = "testcases"
1806	} else if os.Class == Device {
1807		if ctx.InstallInData() {
1808			partition = "data"
1809		} else if ctx.InstallInRamdisk() {
1810			if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
1811				partition = "recovery/root/first_stage_ramdisk"
1812			} else {
1813				partition = "ramdisk"
1814			}
1815			if !ctx.InstallInRoot() {
1816				partition += "/system"
1817			}
1818		} else if ctx.InstallInVendorRamdisk() {
1819			// The module is only available after switching root into
1820			// /first_stage_ramdisk. To expose the module before switching root
1821			// on a device without a dedicated recovery partition, install the
1822			// recovery variant.
1823			if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
1824				partition = "vendor_ramdisk/first_stage_ramdisk"
1825			} else {
1826				partition = "vendor_ramdisk"
1827			}
1828			if !ctx.InstallInRoot() {
1829				partition += "/system"
1830			}
1831		} else if ctx.InstallInDebugRamdisk() {
1832			partition = "debug_ramdisk"
1833		} else if ctx.InstallInRecovery() {
1834			if ctx.InstallInRoot() {
1835				partition = "recovery/root"
1836			} else {
1837				// the layout of recovery partion is the same as that of system partition
1838				partition = "recovery/root/system"
1839			}
1840		} else if ctx.SocSpecific() {
1841			partition = ctx.DeviceConfig().VendorPath()
1842		} else if ctx.DeviceSpecific() {
1843			partition = ctx.DeviceConfig().OdmPath()
1844		} else if ctx.ProductSpecific() {
1845			partition = ctx.DeviceConfig().ProductPath()
1846		} else if ctx.SystemExtSpecific() {
1847			partition = ctx.DeviceConfig().SystemExtPath()
1848		} else if ctx.InstallInRoot() {
1849			partition = "root"
1850		} else {
1851			partition = "system"
1852		}
1853		if ctx.InstallInSanitizerDir() {
1854			partition = "data/asan/" + partition
1855		}
1856	}
1857	return partition
1858}
1859
1860type InstallPaths []InstallPath
1861
1862// Paths returns the InstallPaths as a Paths
1863func (p InstallPaths) Paths() Paths {
1864	if p == nil {
1865		return nil
1866	}
1867	ret := make(Paths, len(p))
1868	for i, path := range p {
1869		ret[i] = path
1870	}
1871	return ret
1872}
1873
1874// Strings returns the string forms of the install paths.
1875func (p InstallPaths) Strings() []string {
1876	if p == nil {
1877		return nil
1878	}
1879	ret := make([]string, len(p))
1880	for i, path := range p {
1881		ret[i] = path.String()
1882	}
1883	return ret
1884}
1885
1886// validateSafePath validates a path that we trust (may contain ninja variables).
1887// Ensures that each path component does not attempt to leave its component.
1888func validateSafePath(pathComponents ...string) (string, error) {
1889	for _, path := range pathComponents {
1890		path := filepath.Clean(path)
1891		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
1892			return "", fmt.Errorf("Path is outside directory: %s", path)
1893		}
1894	}
1895	// TODO: filepath.Join isn't necessarily correct with embedded ninja
1896	// variables. '..' may remove the entire ninja variable, even if it
1897	// will be expanded to multiple nested directories.
1898	return filepath.Join(pathComponents...), nil
1899}
1900
1901// validatePath validates that a path does not include ninja variables, and that
1902// each path component does not attempt to leave its component. Returns a joined
1903// version of each path component.
1904func validatePath(pathComponents ...string) (string, error) {
1905	for _, path := range pathComponents {
1906		if strings.Contains(path, "$") {
1907			return "", fmt.Errorf("Path contains invalid character($): %s", path)
1908		}
1909	}
1910	return validateSafePath(pathComponents...)
1911}
1912
1913func PathForPhony(ctx PathContext, phony string) WritablePath {
1914	if strings.ContainsAny(phony, "$/") {
1915		ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
1916	}
1917	return PhonyPath{basePath{phony, ""}}
1918}
1919
1920type PhonyPath struct {
1921	basePath
1922}
1923
1924func (p PhonyPath) writablePath() {}
1925
1926func (p PhonyPath) getSoongOutDir() string {
1927	// A phone path cannot contain any / so cannot be relative to the build directory.
1928	return ""
1929}
1930
1931func (p PhonyPath) RelativeToTop() Path {
1932	ensureTestOnly()
1933	// A phony path cannot contain any / so does not have a build directory so switching to a new
1934	// build directory has no effect so just return this path.
1935	return p
1936}
1937
1938func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
1939	panic("Not implemented")
1940}
1941
1942var _ Path = PhonyPath{}
1943var _ WritablePath = PhonyPath{}
1944
1945type testPath struct {
1946	basePath
1947}
1948
1949func (p testPath) RelativeToTop() Path {
1950	ensureTestOnly()
1951	return p
1952}
1953
1954func (p testPath) String() string {
1955	return p.path
1956}
1957
1958var _ Path = testPath{}
1959
1960// PathForTesting returns a Path constructed from joining the elements of paths with '/'.  It should only be used from
1961// within tests.
1962func PathForTesting(paths ...string) Path {
1963	p, err := validateSafePath(paths...)
1964	if err != nil {
1965		panic(err)
1966	}
1967	return testPath{basePath{path: p, rel: p}}
1968}
1969
1970// PathsForTesting returns a Path constructed from each element in strs. It should only be used from within tests.
1971func PathsForTesting(strs ...string) Paths {
1972	p := make(Paths, len(strs))
1973	for i, s := range strs {
1974		p[i] = PathForTesting(s)
1975	}
1976
1977	return p
1978}
1979
1980type testPathContext struct {
1981	config Config
1982}
1983
1984func (x *testPathContext) Config() Config             { return x.config }
1985func (x *testPathContext) AddNinjaFileDeps(...string) {}
1986
1987// PathContextForTesting returns a PathContext that can be used in tests, for example to create an OutputPath with
1988// PathForOutput.
1989func PathContextForTesting(config Config) PathContext {
1990	return &testPathContext{
1991		config: config,
1992	}
1993}
1994
1995type testModuleInstallPathContext struct {
1996	baseModuleContext
1997
1998	inData          bool
1999	inTestcases     bool
2000	inSanitizerDir  bool
2001	inRamdisk       bool
2002	inVendorRamdisk bool
2003	inDebugRamdisk  bool
2004	inRecovery      bool
2005	inRoot          bool
2006	forceOS         *OsType
2007	forceArch       *ArchType
2008}
2009
2010func (m testModuleInstallPathContext) Config() Config {
2011	return m.baseModuleContext.config
2012}
2013
2014func (testModuleInstallPathContext) AddNinjaFileDeps(deps ...string) {}
2015
2016func (m testModuleInstallPathContext) InstallInData() bool {
2017	return m.inData
2018}
2019
2020func (m testModuleInstallPathContext) InstallInTestcases() bool {
2021	return m.inTestcases
2022}
2023
2024func (m testModuleInstallPathContext) InstallInSanitizerDir() bool {
2025	return m.inSanitizerDir
2026}
2027
2028func (m testModuleInstallPathContext) InstallInRamdisk() bool {
2029	return m.inRamdisk
2030}
2031
2032func (m testModuleInstallPathContext) InstallInVendorRamdisk() bool {
2033	return m.inVendorRamdisk
2034}
2035
2036func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool {
2037	return m.inDebugRamdisk
2038}
2039
2040func (m testModuleInstallPathContext) InstallInRecovery() bool {
2041	return m.inRecovery
2042}
2043
2044func (m testModuleInstallPathContext) InstallInRoot() bool {
2045	return m.inRoot
2046}
2047
2048func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
2049	return m.forceOS, m.forceArch
2050}
2051
2052// Construct a minimal ModuleInstallPathContext for testing. Note that baseModuleContext is
2053// default-initialized, which leaves blueprint.baseModuleContext set to nil, so methods that are
2054// delegated to it will panic.
2055func ModuleInstallPathContextForTesting(config Config) ModuleInstallPathContext {
2056	ctx := &testModuleInstallPathContext{}
2057	ctx.config = config
2058	ctx.os = Android
2059	return ctx
2060}
2061
2062// Rel performs the same function as filepath.Rel, but reports errors to a PathContext, and reports an error if
2063// targetPath is not inside basePath.
2064func Rel(ctx PathContext, basePath string, targetPath string) string {
2065	rel, isRel := MaybeRel(ctx, basePath, targetPath)
2066	if !isRel {
2067		ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
2068		return ""
2069	}
2070	return rel
2071}
2072
2073// MaybeRel performs the same function as filepath.Rel, but reports errors to a PathContext, and returns false if
2074// targetPath is not inside basePath.
2075func MaybeRel(ctx PathContext, basePath string, targetPath string) (string, bool) {
2076	rel, isRel, err := maybeRelErr(basePath, targetPath)
2077	if err != nil {
2078		reportPathError(ctx, err)
2079	}
2080	return rel, isRel
2081}
2082
2083func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
2084	// filepath.Rel returns an error if one path is absolute and the other is not, handle that case first.
2085	if filepath.IsAbs(basePath) != filepath.IsAbs(targetPath) {
2086		return "", false, nil
2087	}
2088	rel, err := filepath.Rel(basePath, targetPath)
2089	if err != nil {
2090		return "", false, err
2091	} else if rel == ".." || strings.HasPrefix(rel, "../") || strings.HasPrefix(rel, "/") {
2092		return "", false, nil
2093	}
2094	return rel, true, nil
2095}
2096
2097// Writes a file to the output directory.  Attempting to write directly to the output directory
2098// will fail due to the sandbox of the soong_build process.
2099func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
2100	absPath := absolutePath(path.String())
2101	err := os.MkdirAll(filepath.Dir(absPath), 0777)
2102	if err != nil {
2103		return err
2104	}
2105	return ioutil.WriteFile(absPath, data, perm)
2106}
2107
2108func RemoveAllOutputDir(path WritablePath) error {
2109	return os.RemoveAll(absolutePath(path.String()))
2110}
2111
2112func CreateOutputDirIfNonexistent(path WritablePath, perm os.FileMode) error {
2113	dir := absolutePath(path.String())
2114	return createDirIfNonexistent(dir, perm)
2115}
2116
2117func createDirIfNonexistent(dir string, perm os.FileMode) error {
2118	if _, err := os.Stat(dir); os.IsNotExist(err) {
2119		return os.MkdirAll(dir, os.ModePerm)
2120	} else {
2121		return err
2122	}
2123}
2124
2125// absolutePath is deliberately private so that Soong's Go plugins can't use it to find and
2126// read arbitrary files without going through the methods in the current package that track
2127// dependencies.
2128func absolutePath(path string) string {
2129	if filepath.IsAbs(path) {
2130		return path
2131	}
2132	return filepath.Join(absSrcDir, path)
2133}
2134
2135// A DataPath represents the path of a file to be used as data, for example
2136// a test library to be installed alongside a test.
2137// The data file should be installed (copied from `<SrcPath>`) to
2138// `<install_root>/<RelativeInstallPath>/<filename>`, or
2139// `<install_root>/<filename>` if RelativeInstallPath is empty.
2140type DataPath struct {
2141	// The path of the data file that should be copied into the data directory
2142	SrcPath Path
2143	// The install path of the data file, relative to the install root.
2144	RelativeInstallPath string
2145}
2146
2147// PathsIfNonNil returns a Paths containing only the non-nil input arguments.
2148func PathsIfNonNil(paths ...Path) Paths {
2149	if len(paths) == 0 {
2150		// Fast path for empty argument list
2151		return nil
2152	} else if len(paths) == 1 {
2153		// Fast path for a single argument
2154		if paths[0] != nil {
2155			return paths
2156		} else {
2157			return nil
2158		}
2159	}
2160	ret := make(Paths, 0, len(paths))
2161	for _, path := range paths {
2162		if path != nil {
2163			ret = append(ret, path)
2164		}
2165	}
2166	if len(ret) == 0 {
2167		return nil
2168	}
2169	return ret
2170}
2171
2172var thirdPartyDirPrefixExceptions = []*regexp.Regexp{
2173	regexp.MustCompile("^vendor/[^/]*google[^/]*/"),
2174	regexp.MustCompile("^hardware/google/"),
2175	regexp.MustCompile("^hardware/interfaces/"),
2176	regexp.MustCompile("^hardware/libhardware[^/]*/"),
2177	regexp.MustCompile("^hardware/ril/"),
2178}
2179
2180func IsThirdPartyPath(path string) bool {
2181	thirdPartyDirPrefixes := []string{"external/", "vendor/", "hardware/"}
2182
2183	if HasAnyPrefix(path, thirdPartyDirPrefixes) {
2184		for _, prefix := range thirdPartyDirPrefixExceptions {
2185			if prefix.MatchString(path) {
2186				return false
2187			}
2188		}
2189		return true
2190	}
2191	return false
2192}
2193
2194// PathsDepSet is a thin type-safe wrapper around the generic depSet.  It always uses
2195// topological order.
2196type PathsDepSet struct {
2197	depSet
2198}
2199
2200// newPathsDepSet returns an immutable PathsDepSet with the given direct and
2201// transitive contents.
2202func newPathsDepSet(direct Paths, transitive []*PathsDepSet) *PathsDepSet {
2203	return &PathsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)}
2204}
2205
2206// ToList returns the PathsDepSet flattened to a list in topological order.
2207func (d *PathsDepSet) ToList() Paths {
2208	if d == nil {
2209		return nil
2210	}
2211	return d.depSet.ToList().(Paths)
2212}
2213