• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18	"fmt"
19	"io/ioutil"
20	"os"
21	"path/filepath"
22	"reflect"
23	"sort"
24	"strings"
25
26	"github.com/google/blueprint"
27	"github.com/google/blueprint/pathtools"
28)
29
30var absSrcDir string
31
32// PathContext is the subset of a (Module|Singleton)Context required by the
33// Path methods.
34type PathContext interface {
35	Config() Config
36	AddNinjaFileDeps(deps ...string)
37}
38
39type PathGlobContext interface {
40	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
41}
42
43var _ PathContext = SingletonContext(nil)
44var _ PathContext = ModuleContext(nil)
45
46type ModuleInstallPathContext interface {
47	BaseModuleContext
48
49	InstallInData() bool
50	InstallInTestcases() bool
51	InstallInSanitizerDir() bool
52	InstallInRamdisk() bool
53	InstallInRecovery() bool
54	InstallInRoot() bool
55	InstallBypassMake() bool
56}
57
58var _ ModuleInstallPathContext = ModuleContext(nil)
59
60// errorfContext is the interface containing the Errorf method matching the
61// Errorf method in blueprint.SingletonContext.
62type errorfContext interface {
63	Errorf(format string, args ...interface{})
64}
65
66var _ errorfContext = blueprint.SingletonContext(nil)
67
68// moduleErrorf is the interface containing the ModuleErrorf method matching
69// the ModuleErrorf method in blueprint.ModuleContext.
70type moduleErrorf interface {
71	ModuleErrorf(format string, args ...interface{})
72}
73
74var _ moduleErrorf = blueprint.ModuleContext(nil)
75
76// reportPathError will register an error with the attached context. It
77// attempts ctx.ModuleErrorf for a better error message first, then falls
78// back to ctx.Errorf.
79func reportPathError(ctx PathContext, err error) {
80	reportPathErrorf(ctx, "%s", err.Error())
81}
82
83// reportPathErrorf will register an error with the attached context. It
84// attempts ctx.ModuleErrorf for a better error message first, then falls
85// back to ctx.Errorf.
86func reportPathErrorf(ctx PathContext, format string, args ...interface{}) {
87	if mctx, ok := ctx.(moduleErrorf); ok {
88		mctx.ModuleErrorf(format, args...)
89	} else if ectx, ok := ctx.(errorfContext); ok {
90		ectx.Errorf(format, args...)
91	} else {
92		panic(fmt.Sprintf(format, args...))
93	}
94}
95
96func pathContextName(ctx PathContext, module blueprint.Module) string {
97	if x, ok := ctx.(interface{ ModuleName(blueprint.Module) string }); ok {
98		return x.ModuleName(module)
99	} else if x, ok := ctx.(interface{ OtherModuleName(blueprint.Module) string }); ok {
100		return x.OtherModuleName(module)
101	}
102	return "unknown"
103}
104
105type Path interface {
106	// Returns the path in string form
107	String() string
108
109	// Ext returns the extension of the last element of the path
110	Ext() string
111
112	// Base returns the last element of the path
113	Base() string
114
115	// Rel returns the portion of the path relative to the directory it was created from.  For
116	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
117	// directory, and OutputPath.Join("foo").Rel() would return "foo".
118	Rel() string
119}
120
121// WritablePath is a type of path that can be used as an output for build rules.
122type WritablePath interface {
123	Path
124
125	// return the path to the build directory.
126	buildDir() string
127
128	// the writablePath method doesn't directly do anything,
129	// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
130	writablePath()
131}
132
133type genPathProvider interface {
134	genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath
135}
136type objPathProvider interface {
137	objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath
138}
139type resPathProvider interface {
140	resPathWithName(ctx ModuleContext, name string) ModuleResPath
141}
142
143// GenPathWithExt derives a new file path in ctx's generated sources directory
144// from the current path, but with the new extension.
145func GenPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleGenPath {
146	if path, ok := p.(genPathProvider); ok {
147		return path.genPathWithExt(ctx, subdir, ext)
148	}
149	reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
150	return PathForModuleGen(ctx)
151}
152
153// ObjPathWithExt derives a new file path in ctx's object directory from the
154// current path, but with the new extension.
155func ObjPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleObjPath {
156	if path, ok := p.(objPathProvider); ok {
157		return path.objPathWithExt(ctx, subdir, ext)
158	}
159	reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
160	return PathForModuleObj(ctx)
161}
162
163// ResPathWithName derives a new path in ctx's output resource directory, using
164// the current path to create the directory name, and the `name` argument for
165// the filename.
166func ResPathWithName(ctx ModuleContext, p Path, name string) ModuleResPath {
167	if path, ok := p.(resPathProvider); ok {
168		return path.resPathWithName(ctx, name)
169	}
170	reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
171	return PathForModuleRes(ctx)
172}
173
174// OptionalPath is a container that may or may not contain a valid Path.
175type OptionalPath struct {
176	valid bool
177	path  Path
178}
179
180// OptionalPathForPath returns an OptionalPath containing the path.
181func OptionalPathForPath(path Path) OptionalPath {
182	if path == nil {
183		return OptionalPath{}
184	}
185	return OptionalPath{valid: true, path: path}
186}
187
188// Valid returns whether there is a valid path
189func (p OptionalPath) Valid() bool {
190	return p.valid
191}
192
193// Path returns the Path embedded in this OptionalPath. You must be sure that
194// there is a valid path, since this method will panic if there is not.
195func (p OptionalPath) Path() Path {
196	if !p.valid {
197		panic("Requesting an invalid path")
198	}
199	return p.path
200}
201
202// String returns the string version of the Path, or "" if it isn't valid.
203func (p OptionalPath) String() string {
204	if p.valid {
205		return p.path.String()
206	} else {
207		return ""
208	}
209}
210
211// Paths is a slice of Path objects, with helpers to operate on the collection.
212type Paths []Path
213
214// PathsForSource returns Paths rooted from SrcDir
215func PathsForSource(ctx PathContext, paths []string) Paths {
216	ret := make(Paths, len(paths))
217	for i, path := range paths {
218		ret[i] = PathForSource(ctx, path)
219	}
220	return ret
221}
222
223// ExistentPathsForSources returns a list of Paths rooted from SrcDir that are
224// found in the tree. If any are not found, they are omitted from the list,
225// and dependencies are added so that we're re-run when they are added.
226func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
227	ret := make(Paths, 0, len(paths))
228	for _, path := range paths {
229		p := ExistentPathForSource(ctx, path)
230		if p.Valid() {
231			ret = append(ret, p.Path())
232		}
233	}
234	return ret
235}
236
237// PathsForModuleSrc returns Paths rooted from the module's local source directory.  It expands globs, references to
238// SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the
239// ":name{.tag}" syntax.  Properties passed as the paths argument must have been annotated with struct tag
240// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
241// path_properties mutator.  If ctx.Config().AllowMissingDependencies() is true then any missing SourceFileProducer or
242// OutputFileProducer dependencies will cause the module to be marked as having missing dependencies.
243func PathsForModuleSrc(ctx ModuleContext, paths []string) Paths {
244	return PathsForModuleSrcExcludes(ctx, paths, nil)
245}
246
247// PathsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding paths listed in
248// the excludes arguments.  It expands globs, references to SourceFileProducer modules using the ":name" syntax, and
249// references to OutputFileProducer modules using the ":name{.tag}" syntax.  Properties passed as the paths or excludes
250// argument must have been annotated with struct tag `android:"path"` so that dependencies on SourceFileProducer modules
251// will have already been handled by the path_properties mutator.  If ctx.Config().AllowMissingDependencies() is
252// true then any missing SourceFileProducer or OutputFileProducer dependencies will cause the module to be marked as
253// having missing dependencies.
254func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Paths {
255	ret, missingDeps := PathsAndMissingDepsForModuleSrcExcludes(ctx, paths, excludes)
256	if ctx.Config().AllowMissingDependencies() {
257		ctx.AddMissingDependencies(missingDeps)
258	} else {
259		for _, m := range missingDeps {
260			ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
261		}
262	}
263	return ret
264}
265
266// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
267type OutputPaths []OutputPath
268
269// Paths returns the OutputPaths as a Paths
270func (p OutputPaths) Paths() Paths {
271	if p == nil {
272		return nil
273	}
274	ret := make(Paths, len(p))
275	for i, path := range p {
276		ret[i] = path
277	}
278	return ret
279}
280
281// Strings returns the string forms of the writable paths.
282func (p OutputPaths) Strings() []string {
283	if p == nil {
284		return nil
285	}
286	ret := make([]string, len(p))
287	for i, path := range p {
288		ret[i] = path.String()
289	}
290	return ret
291}
292
293// PathsAndMissingDepsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding
294// paths listed in the excludes arguments, and a list of missing dependencies.  It expands globs, references to
295// SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the
296// ":name{.tag}" syntax.  Properties passed as the paths or excludes argument must have been annotated with struct tag
297// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
298// path_properties mutator.  If ctx.Config().AllowMissingDependencies() is true then any missing SourceFileProducer or
299// OutputFileProducer dependencies will be returned, and they will NOT cause the module to be marked as having missing
300// dependencies.
301func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) (Paths, []string) {
302	prefix := pathForModuleSrc(ctx).String()
303
304	var expandedExcludes []string
305	if excludes != nil {
306		expandedExcludes = make([]string, 0, len(excludes))
307	}
308
309	var missingExcludeDeps []string
310
311	for _, e := range excludes {
312		if m, t := SrcIsModuleWithTag(e); m != "" {
313			module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
314			if module == nil {
315				missingExcludeDeps = append(missingExcludeDeps, m)
316				continue
317			}
318			if outProducer, ok := module.(OutputFileProducer); ok {
319				outputFiles, err := outProducer.OutputFiles(t)
320				if err != nil {
321					ctx.ModuleErrorf("path dependency %q: %s", e, err)
322				}
323				expandedExcludes = append(expandedExcludes, outputFiles.Strings()...)
324			} else if t != "" {
325				ctx.ModuleErrorf("path dependency %q is not an output file producing module", e)
326			} else if srcProducer, ok := module.(SourceFileProducer); ok {
327				expandedExcludes = append(expandedExcludes, srcProducer.Srcs().Strings()...)
328			} else {
329				ctx.ModuleErrorf("path dependency %q is not a source file producing module", e)
330			}
331		} else {
332			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
333		}
334	}
335
336	if paths == nil {
337		return nil, missingExcludeDeps
338	}
339
340	var missingDeps []string
341
342	expandedSrcFiles := make(Paths, 0, len(paths))
343	for _, s := range paths {
344		srcFiles, err := expandOneSrcPath(ctx, s, expandedExcludes)
345		if depErr, ok := err.(missingDependencyError); ok {
346			missingDeps = append(missingDeps, depErr.missingDeps...)
347		} else if err != nil {
348			reportPathError(ctx, err)
349		}
350		expandedSrcFiles = append(expandedSrcFiles, srcFiles...)
351	}
352
353	return expandedSrcFiles, append(missingDeps, missingExcludeDeps...)
354}
355
356type missingDependencyError struct {
357	missingDeps []string
358}
359
360func (e missingDependencyError) Error() string {
361	return "missing dependencies: " + strings.Join(e.missingDeps, ", ")
362}
363
364func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (Paths, error) {
365	if m, t := SrcIsModuleWithTag(s); m != "" {
366		module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
367		if module == nil {
368			return nil, missingDependencyError{[]string{m}}
369		}
370		if outProducer, ok := module.(OutputFileProducer); ok {
371			outputFiles, err := outProducer.OutputFiles(t)
372			if err != nil {
373				return nil, fmt.Errorf("path dependency %q: %s", s, err)
374			}
375			return outputFiles, nil
376		} else if t != "" {
377			return nil, fmt.Errorf("path dependency %q is not an output file producing module", s)
378		} else if srcProducer, ok := module.(SourceFileProducer); ok {
379			moduleSrcs := srcProducer.Srcs()
380			for _, e := range expandedExcludes {
381				for j := 0; j < len(moduleSrcs); j++ {
382					if moduleSrcs[j].String() == e {
383						moduleSrcs = append(moduleSrcs[:j], moduleSrcs[j+1:]...)
384						j--
385					}
386				}
387			}
388			return moduleSrcs, nil
389		} else {
390			return nil, fmt.Errorf("path dependency %q is not a source file producing module", s)
391		}
392	} else if pathtools.IsGlob(s) {
393		paths := ctx.GlobFiles(pathForModuleSrc(ctx, s).String(), expandedExcludes)
394		return PathsWithModuleSrcSubDir(ctx, paths, ""), nil
395	} else {
396		p := pathForModuleSrc(ctx, s)
397		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
398			reportPathErrorf(ctx, "%s: %s", p, err.Error())
399		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
400			reportPathErrorf(ctx, "module source path %q does not exist", p)
401		}
402
403		j := findStringInSlice(p.String(), expandedExcludes)
404		if j >= 0 {
405			return nil, nil
406		}
407		return Paths{p}, nil
408	}
409}
410
411// pathsForModuleSrcFromFullPath returns Paths rooted from the module's local
412// source directory, but strip the local source directory from the beginning of
413// each string. If incDirs is false, strip paths with a trailing '/' from the list.
414// It intended for use in globs that only list files that exist, so it allows '$' in
415// filenames.
416func pathsForModuleSrcFromFullPath(ctx EarlyModuleContext, paths []string, incDirs bool) Paths {
417	prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
418	if prefix == "./" {
419		prefix = ""
420	}
421	ret := make(Paths, 0, len(paths))
422	for _, p := range paths {
423		if !incDirs && strings.HasSuffix(p, "/") {
424			continue
425		}
426		path := filepath.Clean(p)
427		if !strings.HasPrefix(path, prefix) {
428			reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
429			continue
430		}
431
432		srcPath, err := safePathForSource(ctx, ctx.ModuleDir(), path[len(prefix):])
433		if err != nil {
434			reportPathError(ctx, err)
435			continue
436		}
437
438		srcPath.basePath.rel = srcPath.path
439
440		ret = append(ret, srcPath)
441	}
442	return ret
443}
444
445// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
446// local source directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
447func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
448	if input != nil {
449		return PathsForModuleSrc(ctx, input)
450	}
451	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
452	// is created, we're run again.
453	path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
454	return ctx.Glob(path, nil)
455}
456
457// Strings returns the Paths in string form
458func (p Paths) Strings() []string {
459	if p == nil {
460		return nil
461	}
462	ret := make([]string, len(p))
463	for i, path := range p {
464		ret[i] = path.String()
465	}
466	return ret
467}
468
469func CopyOfPaths(paths Paths) Paths {
470	return append(Paths(nil), paths...)
471}
472
473// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each.  It
474// modifies the Paths slice contents in place, and returns a subslice of the original slice.
475func FirstUniquePaths(list Paths) Paths {
476	k := 0
477outer:
478	for i := 0; i < len(list); i++ {
479		for j := 0; j < k; j++ {
480			if list[i] == list[j] {
481				continue outer
482			}
483		}
484		list[k] = list[i]
485		k++
486	}
487	return list[:k]
488}
489
490// SortedUniquePaths returns what its name says
491func SortedUniquePaths(list Paths) Paths {
492	unique := FirstUniquePaths(list)
493	sort.Slice(unique, func(i, j int) bool {
494		return unique[i].String() < unique[j].String()
495	})
496	return unique
497}
498
499// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each.  It
500// modifies the Paths slice contents in place, and returns a subslice of the original slice.
501func LastUniquePaths(list Paths) Paths {
502	totalSkip := 0
503	for i := len(list) - 1; i >= totalSkip; i-- {
504		skip := 0
505		for j := i - 1; j >= totalSkip; j-- {
506			if list[i] == list[j] {
507				skip++
508			} else {
509				list[j+skip] = list[j]
510			}
511		}
512		totalSkip += skip
513	}
514	return list[totalSkip:]
515}
516
517// ReversePaths returns a copy of a Paths in reverse order.
518func ReversePaths(list Paths) Paths {
519	if list == nil {
520		return nil
521	}
522	ret := make(Paths, len(list))
523	for i := range list {
524		ret[i] = list[len(list)-1-i]
525	}
526	return ret
527}
528
529func indexPathList(s Path, list []Path) int {
530	for i, l := range list {
531		if l == s {
532			return i
533		}
534	}
535
536	return -1
537}
538
539func inPathList(p Path, list []Path) bool {
540	return indexPathList(p, list) != -1
541}
542
543func FilterPathList(list []Path, filter []Path) (remainder []Path, filtered []Path) {
544	return FilterPathListPredicate(list, func(p Path) bool { return inPathList(p, filter) })
545}
546
547func FilterPathListPredicate(list []Path, predicate func(Path) bool) (remainder []Path, filtered []Path) {
548	for _, l := range list {
549		if predicate(l) {
550			filtered = append(filtered, l)
551		} else {
552			remainder = append(remainder, l)
553		}
554	}
555
556	return
557}
558
559// HasExt returns true of any of the paths have extension ext, otherwise false
560func (p Paths) HasExt(ext string) bool {
561	for _, path := range p {
562		if path.Ext() == ext {
563			return true
564		}
565	}
566
567	return false
568}
569
570// FilterByExt returns the subset of the paths that have extension ext
571func (p Paths) FilterByExt(ext string) Paths {
572	ret := make(Paths, 0, len(p))
573	for _, path := range p {
574		if path.Ext() == ext {
575			ret = append(ret, path)
576		}
577	}
578	return ret
579}
580
581// FilterOutByExt returns the subset of the paths that do not have extension ext
582func (p Paths) FilterOutByExt(ext string) Paths {
583	ret := make(Paths, 0, len(p))
584	for _, path := range p {
585		if path.Ext() != ext {
586			ret = append(ret, path)
587		}
588	}
589	return ret
590}
591
592// DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
593// (including subdirectories) are in a contiguous subslice of the list, and can be found in
594// O(log(N)) time using a binary search on the directory prefix.
595type DirectorySortedPaths Paths
596
597func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
598	ret := append(DirectorySortedPaths(nil), paths...)
599	sort.Slice(ret, func(i, j int) bool {
600		return ret[i].String() < ret[j].String()
601	})
602	return ret
603}
604
605// PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
606// that are in the specified directory and its subdirectories.
607func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
608	prefix := filepath.Clean(dir) + "/"
609	start := sort.Search(len(p), func(i int) bool {
610		return prefix < p[i].String()
611	})
612
613	ret := p[start:]
614
615	end := sort.Search(len(ret), func(i int) bool {
616		return !strings.HasPrefix(ret[i].String(), prefix)
617	})
618
619	ret = ret[:end]
620
621	return Paths(ret)
622}
623
624// WritablePaths is a slice of WritablePaths, used for multiple outputs.
625type WritablePaths []WritablePath
626
627// Strings returns the string forms of the writable paths.
628func (p WritablePaths) Strings() []string {
629	if p == nil {
630		return nil
631	}
632	ret := make([]string, len(p))
633	for i, path := range p {
634		ret[i] = path.String()
635	}
636	return ret
637}
638
639// Paths returns the WritablePaths as a Paths
640func (p WritablePaths) Paths() Paths {
641	if p == nil {
642		return nil
643	}
644	ret := make(Paths, len(p))
645	for i, path := range p {
646		ret[i] = path
647	}
648	return ret
649}
650
651type basePath struct {
652	path   string
653	config Config
654	rel    string
655}
656
657func (p basePath) Ext() string {
658	return filepath.Ext(p.path)
659}
660
661func (p basePath) Base() string {
662	return filepath.Base(p.path)
663}
664
665func (p basePath) Rel() string {
666	if p.rel != "" {
667		return p.rel
668	}
669	return p.path
670}
671
672func (p basePath) String() string {
673	return p.path
674}
675
676func (p basePath) withRel(rel string) basePath {
677	p.path = filepath.Join(p.path, rel)
678	p.rel = rel
679	return p
680}
681
682// SourcePath is a Path representing a file path rooted from SrcDir
683type SourcePath struct {
684	basePath
685}
686
687var _ Path = SourcePath{}
688
689func (p SourcePath) withRel(rel string) SourcePath {
690	p.basePath = p.basePath.withRel(rel)
691	return p
692}
693
694// safePathForSource is for paths that we expect are safe -- only for use by go
695// code that is embedding ninja variables in paths
696func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
697	p, err := validateSafePath(pathComponents...)
698	ret := SourcePath{basePath{p, ctx.Config(), ""}}
699	if err != nil {
700		return ret, err
701	}
702
703	// absolute path already checked by validateSafePath
704	if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
705		return ret, fmt.Errorf("source path %q is in output", ret.String())
706	}
707
708	return ret, err
709}
710
711// pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
712func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
713	p, err := validatePath(pathComponents...)
714	ret := SourcePath{basePath{p, ctx.Config(), ""}}
715	if err != nil {
716		return ret, err
717	}
718
719	// absolute path already checked by validatePath
720	if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
721		return ret, fmt.Errorf("source path %q is in output", ret.String())
722	}
723
724	return ret, nil
725}
726
727// existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
728// path does not exist.
729func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
730	var files []string
731
732	if gctx, ok := ctx.(PathGlobContext); ok {
733		// Use glob to produce proper dependencies, even though we only want
734		// a single file.
735		files, err = gctx.GlobWithDeps(path.String(), nil)
736	} else {
737		var deps []string
738		// We cannot add build statements in this context, so we fall back to
739		// AddNinjaFileDeps
740		files, deps, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
741		ctx.AddNinjaFileDeps(deps...)
742	}
743
744	if err != nil {
745		return false, fmt.Errorf("glob: %s", err.Error())
746	}
747
748	return len(files) > 0, nil
749}
750
751// PathForSource joins the provided path components and validates that the result
752// neither escapes the source dir nor is in the out dir.
753// On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
754func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
755	path, err := pathForSource(ctx, pathComponents...)
756	if err != nil {
757		reportPathError(ctx, err)
758	}
759
760	if pathtools.IsGlob(path.String()) {
761		reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
762	}
763
764	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
765		exists, err := existsWithDependencies(ctx, path)
766		if err != nil {
767			reportPathError(ctx, err)
768		}
769		if !exists {
770			modCtx.AddMissingDependencies([]string{path.String()})
771		}
772	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
773		reportPathErrorf(ctx, "%s: %s", path, err.Error())
774	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
775		reportPathErrorf(ctx, "source path %q does not exist", path)
776	}
777	return path
778}
779
780// ExistentPathForSource returns an OptionalPath with the SourcePath if the
781// path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
782// so that the ninja file will be regenerated if the state of the path changes.
783func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
784	path, err := pathForSource(ctx, pathComponents...)
785	if err != nil {
786		reportPathError(ctx, err)
787		return OptionalPath{}
788	}
789
790	if pathtools.IsGlob(path.String()) {
791		reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
792		return OptionalPath{}
793	}
794
795	exists, err := existsWithDependencies(ctx, path)
796	if err != nil {
797		reportPathError(ctx, err)
798		return OptionalPath{}
799	}
800	if !exists {
801		return OptionalPath{}
802	}
803	return OptionalPathForPath(path)
804}
805
806func (p SourcePath) String() string {
807	return filepath.Join(p.config.srcDir, p.path)
808}
809
810// Join creates a new SourcePath with paths... joined with the current path. The
811// provided paths... may not use '..' to escape from the current path.
812func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
813	path, err := validatePath(paths...)
814	if err != nil {
815		reportPathError(ctx, err)
816	}
817	return p.withRel(path)
818}
819
820// join is like Join but does less path validation.
821func (p SourcePath) join(ctx PathContext, paths ...string) SourcePath {
822	path, err := validateSafePath(paths...)
823	if err != nil {
824		reportPathError(ctx, err)
825	}
826	return p.withRel(path)
827}
828
829// OverlayPath returns the overlay for `path' if it exists. This assumes that the
830// SourcePath is the path to a resource overlay directory.
831func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath {
832	var relDir string
833	if srcPath, ok := path.(SourcePath); ok {
834		relDir = srcPath.path
835	} else {
836		reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
837		return OptionalPath{}
838	}
839	dir := filepath.Join(p.config.srcDir, p.path, relDir)
840	// Use Glob so that we are run again if the directory is added.
841	if pathtools.IsGlob(dir) {
842		reportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
843	}
844	paths, err := ctx.GlobWithDeps(dir, nil)
845	if err != nil {
846		reportPathErrorf(ctx, "glob: %s", err.Error())
847		return OptionalPath{}
848	}
849	if len(paths) == 0 {
850		return OptionalPath{}
851	}
852	relPath := Rel(ctx, p.config.srcDir, paths[0])
853	return OptionalPathForPath(PathForSource(ctx, relPath))
854}
855
856// OutputPath is a Path representing an intermediates file path rooted from the build directory
857type OutputPath struct {
858	basePath
859	fullPath string
860}
861
862func (p OutputPath) withRel(rel string) OutputPath {
863	p.basePath = p.basePath.withRel(rel)
864	p.fullPath = filepath.Join(p.fullPath, rel)
865	return p
866}
867
868func (p OutputPath) WithoutRel() OutputPath {
869	p.basePath.rel = filepath.Base(p.basePath.path)
870	return p
871}
872
873func (p OutputPath) buildDir() string {
874	return p.config.buildDir
875}
876
877var _ Path = OutputPath{}
878var _ WritablePath = OutputPath{}
879
880// PathForOutput joins the provided paths and returns an OutputPath that is
881// validated to not escape the build dir.
882// On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
883func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
884	path, err := validatePath(pathComponents...)
885	if err != nil {
886		reportPathError(ctx, err)
887	}
888	fullPath := filepath.Join(ctx.Config().buildDir, path)
889	path = fullPath[len(fullPath)-len(path):]
890	return OutputPath{basePath{path, ctx.Config(), ""}, fullPath}
891}
892
893// PathsForOutput returns Paths rooted from buildDir
894func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
895	ret := make(WritablePaths, len(paths))
896	for i, path := range paths {
897		ret[i] = PathForOutput(ctx, path)
898	}
899	return ret
900}
901
902func (p OutputPath) writablePath() {}
903
904func (p OutputPath) String() string {
905	return p.fullPath
906}
907
908// Join creates a new OutputPath with paths... joined with the current path. The
909// provided paths... may not use '..' to escape from the current path.
910func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
911	path, err := validatePath(paths...)
912	if err != nil {
913		reportPathError(ctx, err)
914	}
915	return p.withRel(path)
916}
917
918// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
919func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
920	if strings.Contains(ext, "/") {
921		reportPathErrorf(ctx, "extension %q cannot contain /", ext)
922	}
923	ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
924	ret.rel = pathtools.ReplaceExtension(p.rel, ext)
925	return ret
926}
927
928// InSameDir creates a new OutputPath from the directory of the current OutputPath joined with the elements in paths.
929func (p OutputPath) InSameDir(ctx PathContext, paths ...string) OutputPath {
930	path, err := validatePath(paths...)
931	if err != nil {
932		reportPathError(ctx, err)
933	}
934
935	ret := PathForOutput(ctx, filepath.Dir(p.path), path)
936	ret.rel = filepath.Join(filepath.Dir(p.rel), path)
937	return ret
938}
939
940// PathForIntermediates returns an OutputPath representing the top-level
941// intermediates directory.
942func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
943	path, err := validatePath(paths...)
944	if err != nil {
945		reportPathError(ctx, err)
946	}
947	return PathForOutput(ctx, ".intermediates", path)
948}
949
950var _ genPathProvider = SourcePath{}
951var _ objPathProvider = SourcePath{}
952var _ resPathProvider = SourcePath{}
953
954// PathForModuleSrc returns a Path representing the paths... under the
955// module's local source directory.
956func PathForModuleSrc(ctx ModuleContext, pathComponents ...string) Path {
957	p, err := validatePath(pathComponents...)
958	if err != nil {
959		reportPathError(ctx, err)
960	}
961	paths, err := expandOneSrcPath(ctx, p, nil)
962	if err != nil {
963		if depErr, ok := err.(missingDependencyError); ok {
964			if ctx.Config().AllowMissingDependencies() {
965				ctx.AddMissingDependencies(depErr.missingDeps)
966			} else {
967				ctx.ModuleErrorf(`%s, is the property annotated with android:"path"?`, depErr.Error())
968			}
969		} else {
970			reportPathError(ctx, err)
971		}
972		return nil
973	} else if len(paths) == 0 {
974		reportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
975		return nil
976	} else if len(paths) > 1 {
977		reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
978	}
979	return paths[0]
980}
981
982func pathForModuleSrc(ctx ModuleContext, paths ...string) SourcePath {
983	p, err := validatePath(paths...)
984	if err != nil {
985		reportPathError(ctx, err)
986	}
987
988	path, err := pathForSource(ctx, ctx.ModuleDir(), p)
989	if err != nil {
990		reportPathError(ctx, err)
991	}
992
993	path.basePath.rel = p
994
995	return path
996}
997
998// PathsWithModuleSrcSubDir takes a list of Paths and returns a new list of Paths where Rel() on each path
999// will return the path relative to subDir in the module's source directory.  If any input paths are not located
1000// inside subDir then a path error will be reported.
1001func PathsWithModuleSrcSubDir(ctx ModuleContext, paths Paths, subDir string) Paths {
1002	paths = append(Paths(nil), paths...)
1003	subDirFullPath := pathForModuleSrc(ctx, subDir)
1004	for i, path := range paths {
1005		rel := Rel(ctx, subDirFullPath.String(), path.String())
1006		paths[i] = subDirFullPath.join(ctx, rel)
1007	}
1008	return paths
1009}
1010
1011// PathWithModuleSrcSubDir takes a Path and returns a Path where Rel() will return the path relative to subDir in the
1012// module's source directory.  If the input path is not located inside subDir then a path error will be reported.
1013func PathWithModuleSrcSubDir(ctx ModuleContext, path Path, subDir string) Path {
1014	subDirFullPath := pathForModuleSrc(ctx, subDir)
1015	rel := Rel(ctx, subDirFullPath.String(), path.String())
1016	return subDirFullPath.Join(ctx, rel)
1017}
1018
1019// OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
1020// valid path if p is non-nil.
1021func OptionalPathForModuleSrc(ctx ModuleContext, p *string) OptionalPath {
1022	if p == nil {
1023		return OptionalPath{}
1024	}
1025	return OptionalPathForPath(PathForModuleSrc(ctx, *p))
1026}
1027
1028func (p SourcePath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
1029	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1030}
1031
1032func (p SourcePath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
1033	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1034}
1035
1036func (p SourcePath) resPathWithName(ctx ModuleContext, name string) ModuleResPath {
1037	// TODO: Use full directory if the new ctx is not the current ctx?
1038	return PathForModuleRes(ctx, p.path, name)
1039}
1040
1041// ModuleOutPath is a Path representing a module's output directory.
1042type ModuleOutPath struct {
1043	OutputPath
1044}
1045
1046var _ Path = ModuleOutPath{}
1047
1048func (p ModuleOutPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
1049	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1050}
1051
1052func pathForModule(ctx ModuleContext) OutputPath {
1053	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
1054}
1055
1056// PathForVndkRefAbiDump returns an OptionalPath representing the path of the
1057// reference abi dump for the given module. This is not guaranteed to be valid.
1058func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
1059	isNdk, isLlndkOrVndk, isGzip bool) OptionalPath {
1060
1061	arches := ctx.DeviceConfig().Arches()
1062	if len(arches) == 0 {
1063		panic("device build with no primary arch")
1064	}
1065	currentArch := ctx.Arch()
1066	archNameAndVariant := currentArch.ArchType.String()
1067	if currentArch.ArchVariant != "" {
1068		archNameAndVariant += "_" + currentArch.ArchVariant
1069	}
1070
1071	var dirName string
1072	if isNdk {
1073		dirName = "ndk"
1074	} else if isLlndkOrVndk {
1075		dirName = "vndk"
1076	} else {
1077		dirName = "platform" // opt-in libs
1078	}
1079
1080	binderBitness := ctx.DeviceConfig().BinderBitness()
1081
1082	var ext string
1083	if isGzip {
1084		ext = ".lsdump.gz"
1085	} else {
1086		ext = ".lsdump"
1087	}
1088
1089	return ExistentPathForSource(ctx, "prebuilts", "abi-dumps", dirName,
1090		version, binderBitness, archNameAndVariant, "source-based",
1091		fileName+ext)
1092}
1093
1094// PathForModuleOut returns a Path representing the paths... under the module's
1095// output directory.
1096func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
1097	p, err := validatePath(paths...)
1098	if err != nil {
1099		reportPathError(ctx, err)
1100	}
1101	return ModuleOutPath{
1102		OutputPath: pathForModule(ctx).withRel(p),
1103	}
1104}
1105
1106// ModuleGenPath is a Path representing the 'gen' directory in a module's output
1107// directory. Mainly used for generated sources.
1108type ModuleGenPath struct {
1109	ModuleOutPath
1110}
1111
1112var _ Path = ModuleGenPath{}
1113var _ genPathProvider = ModuleGenPath{}
1114var _ objPathProvider = ModuleGenPath{}
1115
1116// PathForModuleGen returns a Path representing the paths... under the module's
1117// `gen' directory.
1118func PathForModuleGen(ctx ModuleContext, paths ...string) ModuleGenPath {
1119	p, err := validatePath(paths...)
1120	if err != nil {
1121		reportPathError(ctx, err)
1122	}
1123	return ModuleGenPath{
1124		ModuleOutPath: ModuleOutPath{
1125			OutputPath: pathForModule(ctx).withRel("gen").withRel(p),
1126		},
1127	}
1128}
1129
1130func (p ModuleGenPath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
1131	// TODO: make a different path for local vs remote generated files?
1132	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1133}
1134
1135func (p ModuleGenPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
1136	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1137}
1138
1139// ModuleObjPath is a Path representing the 'obj' directory in a module's output
1140// directory. Used for compiled objects.
1141type ModuleObjPath struct {
1142	ModuleOutPath
1143}
1144
1145var _ Path = ModuleObjPath{}
1146
1147// PathForModuleObj returns a Path representing the paths... under the module's
1148// 'obj' directory.
1149func PathForModuleObj(ctx ModuleContext, pathComponents ...string) ModuleObjPath {
1150	p, err := validatePath(pathComponents...)
1151	if err != nil {
1152		reportPathError(ctx, err)
1153	}
1154	return ModuleObjPath{PathForModuleOut(ctx, "obj", p)}
1155}
1156
1157// ModuleResPath is a a Path representing the 'res' directory in a module's
1158// output directory.
1159type ModuleResPath struct {
1160	ModuleOutPath
1161}
1162
1163var _ Path = ModuleResPath{}
1164
1165// PathForModuleRes returns a Path representing the paths... under the module's
1166// 'res' directory.
1167func PathForModuleRes(ctx ModuleContext, pathComponents ...string) ModuleResPath {
1168	p, err := validatePath(pathComponents...)
1169	if err != nil {
1170		reportPathError(ctx, err)
1171	}
1172
1173	return ModuleResPath{PathForModuleOut(ctx, "res", p)}
1174}
1175
1176// InstallPath is a Path representing a installed file path rooted from the build directory
1177type InstallPath struct {
1178	basePath
1179
1180	baseDir string // "../" for Make paths to convert "out/soong" to "out", "" for Soong paths
1181}
1182
1183func (p InstallPath) buildDir() string {
1184	return p.config.buildDir
1185}
1186
1187var _ Path = InstallPath{}
1188var _ WritablePath = InstallPath{}
1189
1190func (p InstallPath) writablePath() {}
1191
1192func (p InstallPath) String() string {
1193	return filepath.Join(p.config.buildDir, p.baseDir, p.path)
1194}
1195
1196// Join creates a new InstallPath with paths... joined with the current path. The
1197// provided paths... may not use '..' to escape from the current path.
1198func (p InstallPath) Join(ctx PathContext, paths ...string) InstallPath {
1199	path, err := validatePath(paths...)
1200	if err != nil {
1201		reportPathError(ctx, err)
1202	}
1203	return p.withRel(path)
1204}
1205
1206func (p InstallPath) withRel(rel string) InstallPath {
1207	p.basePath = p.basePath.withRel(rel)
1208	return p
1209}
1210
1211// ToMakePath returns a new InstallPath that points to Make's install directory instead of Soong's,
1212// i.e. out/ instead of out/soong/.
1213func (p InstallPath) ToMakePath() InstallPath {
1214	p.baseDir = "../"
1215	return p
1216}
1217
1218// PathForModuleInstall returns a Path representing the install path for the
1219// module appended with paths...
1220func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
1221	var outPaths []string
1222	if ctx.Device() {
1223		partition := modulePartition(ctx)
1224		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
1225	} else {
1226		switch ctx.Os() {
1227		case Linux:
1228			outPaths = []string{"host", "linux-x86"}
1229		case LinuxBionic:
1230			// TODO: should this be a separate top level, or shared with linux-x86?
1231			outPaths = []string{"host", "linux_bionic-x86"}
1232		default:
1233			outPaths = []string{"host", ctx.Os().String() + "-x86"}
1234		}
1235	}
1236	if ctx.Debug() {
1237		outPaths = append([]string{"debug"}, outPaths...)
1238	}
1239	outPaths = append(outPaths, pathComponents...)
1240
1241	path, err := validatePath(outPaths...)
1242	if err != nil {
1243		reportPathError(ctx, err)
1244	}
1245
1246	ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
1247	if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
1248		ret = ret.ToMakePath()
1249	}
1250
1251	return ret
1252}
1253
1254func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
1255	paths = append([]string{prefix}, paths...)
1256	path, err := validatePath(paths...)
1257	if err != nil {
1258		reportPathError(ctx, err)
1259	}
1260	return InstallPath{basePath{path, ctx.Config(), ""}, ""}
1261}
1262
1263func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
1264	return pathForNdkOrSdkInstall(ctx, "ndk", paths)
1265}
1266
1267func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
1268	return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
1269}
1270
1271func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
1272	rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
1273
1274	return "/" + rel
1275}
1276
1277func modulePartition(ctx ModuleInstallPathContext) string {
1278	var partition string
1279	if ctx.InstallInData() {
1280		partition = "data"
1281	} else if ctx.InstallInTestcases() {
1282		partition = "testcases"
1283	} else if ctx.InstallInRamdisk() {
1284		if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
1285			partition = "recovery/root/first_stage_ramdisk"
1286		} else {
1287			partition = "ramdisk"
1288		}
1289		if !ctx.InstallInRoot() {
1290			partition += "/system"
1291		}
1292	} else if ctx.InstallInRecovery() {
1293		if ctx.InstallInRoot() {
1294			partition = "recovery/root"
1295		} else {
1296			// the layout of recovery partion is the same as that of system partition
1297			partition = "recovery/root/system"
1298		}
1299	} else if ctx.SocSpecific() {
1300		partition = ctx.DeviceConfig().VendorPath()
1301	} else if ctx.DeviceSpecific() {
1302		partition = ctx.DeviceConfig().OdmPath()
1303	} else if ctx.ProductSpecific() {
1304		partition = ctx.DeviceConfig().ProductPath()
1305	} else if ctx.SystemExtSpecific() {
1306		partition = ctx.DeviceConfig().SystemExtPath()
1307	} else if ctx.InstallInRoot() {
1308		partition = "root"
1309	} else {
1310		partition = "system"
1311	}
1312	if ctx.InstallInSanitizerDir() {
1313		partition = "data/asan/" + partition
1314	}
1315	return partition
1316}
1317
1318// validateSafePath validates a path that we trust (may contain ninja variables).
1319// Ensures that each path component does not attempt to leave its component.
1320func validateSafePath(pathComponents ...string) (string, error) {
1321	for _, path := range pathComponents {
1322		path := filepath.Clean(path)
1323		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
1324			return "", fmt.Errorf("Path is outside directory: %s", path)
1325		}
1326	}
1327	// TODO: filepath.Join isn't necessarily correct with embedded ninja
1328	// variables. '..' may remove the entire ninja variable, even if it
1329	// will be expanded to multiple nested directories.
1330	return filepath.Join(pathComponents...), nil
1331}
1332
1333// validatePath validates that a path does not include ninja variables, and that
1334// each path component does not attempt to leave its component. Returns a joined
1335// version of each path component.
1336func validatePath(pathComponents ...string) (string, error) {
1337	for _, path := range pathComponents {
1338		if strings.Contains(path, "$") {
1339			return "", fmt.Errorf("Path contains invalid character($): %s", path)
1340		}
1341	}
1342	return validateSafePath(pathComponents...)
1343}
1344
1345func PathForPhony(ctx PathContext, phony string) WritablePath {
1346	if strings.ContainsAny(phony, "$/") {
1347		reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
1348	}
1349	return PhonyPath{basePath{phony, ctx.Config(), ""}}
1350}
1351
1352type PhonyPath struct {
1353	basePath
1354}
1355
1356func (p PhonyPath) writablePath() {}
1357
1358func (p PhonyPath) buildDir() string {
1359	return p.config.buildDir
1360}
1361
1362var _ Path = PhonyPath{}
1363var _ WritablePath = PhonyPath{}
1364
1365type testPath struct {
1366	basePath
1367}
1368
1369func (p testPath) String() string {
1370	return p.path
1371}
1372
1373// PathForTesting returns a Path constructed from joining the elements of paths with '/'.  It should only be used from
1374// within tests.
1375func PathForTesting(paths ...string) Path {
1376	p, err := validateSafePath(paths...)
1377	if err != nil {
1378		panic(err)
1379	}
1380	return testPath{basePath{path: p, rel: p}}
1381}
1382
1383// PathsForTesting returns a Path constructed from each element in strs. It should only be used from within tests.
1384func PathsForTesting(strs ...string) Paths {
1385	p := make(Paths, len(strs))
1386	for i, s := range strs {
1387		p[i] = PathForTesting(s)
1388	}
1389
1390	return p
1391}
1392
1393type testPathContext struct {
1394	config Config
1395}
1396
1397func (x *testPathContext) Config() Config             { return x.config }
1398func (x *testPathContext) AddNinjaFileDeps(...string) {}
1399
1400// PathContextForTesting returns a PathContext that can be used in tests, for example to create an OutputPath with
1401// PathForOutput.
1402func PathContextForTesting(config Config) PathContext {
1403	return &testPathContext{
1404		config: config,
1405	}
1406}
1407
1408// Rel performs the same function as filepath.Rel, but reports errors to a PathContext, and reports an error if
1409// targetPath is not inside basePath.
1410func Rel(ctx PathContext, basePath string, targetPath string) string {
1411	rel, isRel := MaybeRel(ctx, basePath, targetPath)
1412	if !isRel {
1413		reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
1414		return ""
1415	}
1416	return rel
1417}
1418
1419// MaybeRel performs the same function as filepath.Rel, but reports errors to a PathContext, and returns false if
1420// targetPath is not inside basePath.
1421func MaybeRel(ctx PathContext, basePath string, targetPath string) (string, bool) {
1422	rel, isRel, err := maybeRelErr(basePath, targetPath)
1423	if err != nil {
1424		reportPathError(ctx, err)
1425	}
1426	return rel, isRel
1427}
1428
1429func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
1430	// filepath.Rel returns an error if one path is absolute and the other is not, handle that case first.
1431	if filepath.IsAbs(basePath) != filepath.IsAbs(targetPath) {
1432		return "", false, nil
1433	}
1434	rel, err := filepath.Rel(basePath, targetPath)
1435	if err != nil {
1436		return "", false, err
1437	} else if rel == ".." || strings.HasPrefix(rel, "../") || strings.HasPrefix(rel, "/") {
1438		return "", false, nil
1439	}
1440	return rel, true, nil
1441}
1442
1443// Writes a file to the output directory.  Attempting to write directly to the output directory
1444// will fail due to the sandbox of the soong_build process.
1445func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
1446	return ioutil.WriteFile(absolutePath(path.String()), data, perm)
1447}
1448
1449func absolutePath(path string) string {
1450	if filepath.IsAbs(path) {
1451		return path
1452	}
1453	return filepath.Join(absSrcDir, path)
1454}
1455