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