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