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