Home | History | Annotate | Download | only in android
      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 
     15 package android
     16 
     17 import (
     18 	"fmt"
     19 	"path/filepath"
     20 	"reflect"
     21 	"sort"
     22 	"strings"
     23 
     24 	"github.com/google/blueprint"
     25 	"github.com/google/blueprint/pathtools"
     26 )
     27 
     28 // PathContext is the subset of a (Module|Singleton)Context required by the
     29 // Path methods.
     30 type PathContext interface {
     31 	Fs() pathtools.FileSystem
     32 	Config() Config
     33 	AddNinjaFileDeps(deps ...string)
     34 }
     35 
     36 type PathGlobContext interface {
     37 	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
     38 }
     39 
     40 var _ PathContext = SingletonContext(nil)
     41 var _ PathContext = ModuleContext(nil)
     42 
     43 type ModuleInstallPathContext interface {
     44 	PathContext
     45 
     46 	androidBaseContext
     47 
     48 	InstallInData() bool
     49 	InstallInSanitizerDir() bool
     50 }
     51 
     52 var _ ModuleInstallPathContext = ModuleContext(nil)
     53 
     54 // errorfContext is the interface containing the Errorf method matching the
     55 // Errorf method in blueprint.SingletonContext.
     56 type errorfContext interface {
     57 	Errorf(format string, args ...interface{})
     58 }
     59 
     60 var _ errorfContext = blueprint.SingletonContext(nil)
     61 
     62 // moduleErrorf is the interface containing the ModuleErrorf method matching
     63 // the ModuleErrorf method in blueprint.ModuleContext.
     64 type moduleErrorf interface {
     65 	ModuleErrorf(format string, args ...interface{})
     66 }
     67 
     68 var _ moduleErrorf = blueprint.ModuleContext(nil)
     69 
     70 // reportPathError will register an error with the attached context. It
     71 // attempts ctx.ModuleErrorf for a better error message first, then falls
     72 // back to ctx.Errorf.
     73 func reportPathError(ctx PathContext, err error) {
     74 	reportPathErrorf(ctx, "%s", err.Error())
     75 }
     76 
     77 // reportPathErrorf will register an error with the attached context. It
     78 // attempts ctx.ModuleErrorf for a better error message first, then falls
     79 // back to ctx.Errorf.
     80 func reportPathErrorf(ctx PathContext, format string, args ...interface{}) {
     81 	if mctx, ok := ctx.(moduleErrorf); ok {
     82 		mctx.ModuleErrorf(format, args...)
     83 	} else if ectx, ok := ctx.(errorfContext); ok {
     84 		ectx.Errorf(format, args...)
     85 	} else {
     86 		panic(fmt.Sprintf(format, args...))
     87 	}
     88 }
     89 
     90 type Path interface {
     91 	// Returns the path in string form
     92 	String() string
     93 
     94 	// Ext returns the extension of the last element of the path
     95 	Ext() string
     96 
     97 	// Base returns the last element of the path
     98 	Base() string
     99 
    100 	// Rel returns the portion of the path relative to the directory it was created from.  For
    101 	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
    102 	// directory, and OutputPath.Join("foo").Rel() would return "foo".
    103 	Rel() string
    104 }
    105 
    106 // WritablePath is a type of path that can be used as an output for build rules.
    107 type WritablePath interface {
    108 	Path
    109 
    110 	// the writablePath method doesn't directly do anything,
    111 	// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
    112 	writablePath()
    113 }
    114 
    115 type genPathProvider interface {
    116 	genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath
    117 }
    118 type objPathProvider interface {
    119 	objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath
    120 }
    121 type resPathProvider interface {
    122 	resPathWithName(ctx ModuleContext, name string) ModuleResPath
    123 }
    124 
    125 // GenPathWithExt derives a new file path in ctx's generated sources directory
    126 // from the current path, but with the new extension.
    127 func GenPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleGenPath {
    128 	if path, ok := p.(genPathProvider); ok {
    129 		return path.genPathWithExt(ctx, subdir, ext)
    130 	}
    131 	reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
    132 	return PathForModuleGen(ctx)
    133 }
    134 
    135 // ObjPathWithExt derives a new file path in ctx's object directory from the
    136 // current path, but with the new extension.
    137 func ObjPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) ModuleObjPath {
    138 	if path, ok := p.(objPathProvider); ok {
    139 		return path.objPathWithExt(ctx, subdir, ext)
    140 	}
    141 	reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
    142 	return PathForModuleObj(ctx)
    143 }
    144 
    145 // ResPathWithName derives a new path in ctx's output resource directory, using
    146 // the current path to create the directory name, and the `name` argument for
    147 // the filename.
    148 func ResPathWithName(ctx ModuleContext, p Path, name string) ModuleResPath {
    149 	if path, ok := p.(resPathProvider); ok {
    150 		return path.resPathWithName(ctx, name)
    151 	}
    152 	reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
    153 	return PathForModuleRes(ctx)
    154 }
    155 
    156 // OptionalPath is a container that may or may not contain a valid Path.
    157 type OptionalPath struct {
    158 	valid bool
    159 	path  Path
    160 }
    161 
    162 // OptionalPathForPath returns an OptionalPath containing the path.
    163 func OptionalPathForPath(path Path) OptionalPath {
    164 	if path == nil {
    165 		return OptionalPath{}
    166 	}
    167 	return OptionalPath{valid: true, path: path}
    168 }
    169 
    170 // Valid returns whether there is a valid path
    171 func (p OptionalPath) Valid() bool {
    172 	return p.valid
    173 }
    174 
    175 // Path returns the Path embedded in this OptionalPath. You must be sure that
    176 // there is a valid path, since this method will panic if there is not.
    177 func (p OptionalPath) Path() Path {
    178 	if !p.valid {
    179 		panic("Requesting an invalid path")
    180 	}
    181 	return p.path
    182 }
    183 
    184 // String returns the string version of the Path, or "" if it isn't valid.
    185 func (p OptionalPath) String() string {
    186 	if p.valid {
    187 		return p.path.String()
    188 	} else {
    189 		return ""
    190 	}
    191 }
    192 
    193 // Paths is a slice of Path objects, with helpers to operate on the collection.
    194 type Paths []Path
    195 
    196 // PathsForSource returns Paths rooted from SrcDir
    197 func PathsForSource(ctx PathContext, paths []string) Paths {
    198 	ret := make(Paths, len(paths))
    199 	for i, path := range paths {
    200 		ret[i] = PathForSource(ctx, path)
    201 	}
    202 	return ret
    203 }
    204 
    205 // ExistentPathsForSources returns a list of Paths rooted from SrcDir that are
    206 // found in the tree. If any are not found, they are omitted from the list,
    207 // and dependencies are added so that we're re-run when they are added.
    208 func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
    209 	ret := make(Paths, 0, len(paths))
    210 	for _, path := range paths {
    211 		p := ExistentPathForSource(ctx, path)
    212 		if p.Valid() {
    213 			ret = append(ret, p.Path())
    214 		}
    215 	}
    216 	return ret
    217 }
    218 
    219 // PathsForModuleSrc returns Paths rooted from the module's local source
    220 // directory
    221 func PathsForModuleSrc(ctx ModuleContext, paths []string) Paths {
    222 	ret := make(Paths, len(paths))
    223 	for i, path := range paths {
    224 		ret[i] = PathForModuleSrc(ctx, path)
    225 	}
    226 	return ret
    227 }
    228 
    229 // pathsForModuleSrcFromFullPath returns Paths rooted from the module's local
    230 // source directory, but strip the local source directory from the beginning of
    231 // each string. If incDirs is false, strip paths with a trailing '/' from the list.
    232 func pathsForModuleSrcFromFullPath(ctx ModuleContext, paths []string, incDirs bool) Paths {
    233 	prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
    234 	if prefix == "./" {
    235 		prefix = ""
    236 	}
    237 	ret := make(Paths, 0, len(paths))
    238 	for _, p := range paths {
    239 		if !incDirs && strings.HasSuffix(p, "/") {
    240 			continue
    241 		}
    242 		path := filepath.Clean(p)
    243 		if !strings.HasPrefix(path, prefix) {
    244 			reportPathErrorf(ctx, "Path '%s' is not in module source directory '%s'", p, prefix)
    245 			continue
    246 		}
    247 		ret = append(ret, PathForModuleSrc(ctx, path[len(prefix):]))
    248 	}
    249 	return ret
    250 }
    251 
    252 // PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
    253 // local source directory. If none are provided, use the default if it exists.
    254 func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
    255 	if len(input) > 0 {
    256 		return PathsForModuleSrc(ctx, input)
    257 	}
    258 	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
    259 	// is created, we're run again.
    260 	path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
    261 	return ctx.Glob(path, nil)
    262 }
    263 
    264 // Strings returns the Paths in string form
    265 func (p Paths) Strings() []string {
    266 	if p == nil {
    267 		return nil
    268 	}
    269 	ret := make([]string, len(p))
    270 	for i, path := range p {
    271 		ret[i] = path.String()
    272 	}
    273 	return ret
    274 }
    275 
    276 // FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each.  It
    277 // modifies the Paths slice contents in place, and returns a subslice of the original slice.
    278 func FirstUniquePaths(list Paths) Paths {
    279 	k := 0
    280 outer:
    281 	for i := 0; i < len(list); i++ {
    282 		for j := 0; j < k; j++ {
    283 			if list[i] == list[j] {
    284 				continue outer
    285 			}
    286 		}
    287 		list[k] = list[i]
    288 		k++
    289 	}
    290 	return list[:k]
    291 }
    292 
    293 // LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each.  It
    294 // modifies the Paths slice contents in place, and returns a subslice of the original slice.
    295 func LastUniquePaths(list Paths) Paths {
    296 	totalSkip := 0
    297 	for i := len(list) - 1; i >= totalSkip; i-- {
    298 		skip := 0
    299 		for j := i - 1; j >= totalSkip; j-- {
    300 			if list[i] == list[j] {
    301 				skip++
    302 			} else {
    303 				list[j+skip] = list[j]
    304 			}
    305 		}
    306 		totalSkip += skip
    307 	}
    308 	return list[totalSkip:]
    309 }
    310 
    311 // ReversePaths returns a copy of a Paths in reverse order.
    312 func ReversePaths(list Paths) Paths {
    313 	if list == nil {
    314 		return nil
    315 	}
    316 	ret := make(Paths, len(list))
    317 	for i := range list {
    318 		ret[i] = list[len(list)-1-i]
    319 	}
    320 	return ret
    321 }
    322 
    323 func indexPathList(s Path, list []Path) int {
    324 	for i, l := range list {
    325 		if l == s {
    326 			return i
    327 		}
    328 	}
    329 
    330 	return -1
    331 }
    332 
    333 func inPathList(p Path, list []Path) bool {
    334 	return indexPathList(p, list) != -1
    335 }
    336 
    337 func FilterPathList(list []Path, filter []Path) (remainder []Path, filtered []Path) {
    338 	for _, l := range list {
    339 		if inPathList(l, filter) {
    340 			filtered = append(filtered, l)
    341 		} else {
    342 			remainder = append(remainder, l)
    343 		}
    344 	}
    345 
    346 	return
    347 }
    348 
    349 // HasExt returns true of any of the paths have extension ext, otherwise false
    350 func (p Paths) HasExt(ext string) bool {
    351 	for _, path := range p {
    352 		if path.Ext() == ext {
    353 			return true
    354 		}
    355 	}
    356 
    357 	return false
    358 }
    359 
    360 // FilterByExt returns the subset of the paths that have extension ext
    361 func (p Paths) FilterByExt(ext string) Paths {
    362 	ret := make(Paths, 0, len(p))
    363 	for _, path := range p {
    364 		if path.Ext() == ext {
    365 			ret = append(ret, path)
    366 		}
    367 	}
    368 	return ret
    369 }
    370 
    371 // FilterOutByExt returns the subset of the paths that do not have extension ext
    372 func (p Paths) FilterOutByExt(ext string) Paths {
    373 	ret := make(Paths, 0, len(p))
    374 	for _, path := range p {
    375 		if path.Ext() != ext {
    376 			ret = append(ret, path)
    377 		}
    378 	}
    379 	return ret
    380 }
    381 
    382 // DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
    383 // (including subdirectories) are in a contiguous subslice of the list, and can be found in
    384 // O(log(N)) time using a binary search on the directory prefix.
    385 type DirectorySortedPaths Paths
    386 
    387 func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
    388 	ret := append(DirectorySortedPaths(nil), paths...)
    389 	sort.Slice(ret, func(i, j int) bool {
    390 		return ret[i].String() < ret[j].String()
    391 	})
    392 	return ret
    393 }
    394 
    395 // PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
    396 // that are in the specified directory and its subdirectories.
    397 func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
    398 	prefix := filepath.Clean(dir) + "/"
    399 	start := sort.Search(len(p), func(i int) bool {
    400 		return prefix < p[i].String()
    401 	})
    402 
    403 	ret := p[start:]
    404 
    405 	end := sort.Search(len(ret), func(i int) bool {
    406 		return !strings.HasPrefix(ret[i].String(), prefix)
    407 	})
    408 
    409 	ret = ret[:end]
    410 
    411 	return Paths(ret)
    412 }
    413 
    414 // WritablePaths is a slice of WritablePaths, used for multiple outputs.
    415 type WritablePaths []WritablePath
    416 
    417 // Strings returns the string forms of the writable paths.
    418 func (p WritablePaths) Strings() []string {
    419 	if p == nil {
    420 		return nil
    421 	}
    422 	ret := make([]string, len(p))
    423 	for i, path := range p {
    424 		ret[i] = path.String()
    425 	}
    426 	return ret
    427 }
    428 
    429 // Paths returns the WritablePaths as a Paths
    430 func (p WritablePaths) Paths() Paths {
    431 	if p == nil {
    432 		return nil
    433 	}
    434 	ret := make(Paths, len(p))
    435 	for i, path := range p {
    436 		ret[i] = path
    437 	}
    438 	return ret
    439 }
    440 
    441 type basePath struct {
    442 	path   string
    443 	config Config
    444 	rel    string
    445 }
    446 
    447 func (p basePath) Ext() string {
    448 	return filepath.Ext(p.path)
    449 }
    450 
    451 func (p basePath) Base() string {
    452 	return filepath.Base(p.path)
    453 }
    454 
    455 func (p basePath) Rel() string {
    456 	if p.rel != "" {
    457 		return p.rel
    458 	}
    459 	return p.path
    460 }
    461 
    462 func (p basePath) String() string {
    463 	return p.path
    464 }
    465 
    466 func (p basePath) withRel(rel string) basePath {
    467 	p.path = filepath.Join(p.path, rel)
    468 	p.rel = rel
    469 	return p
    470 }
    471 
    472 // SourcePath is a Path representing a file path rooted from SrcDir
    473 type SourcePath struct {
    474 	basePath
    475 }
    476 
    477 var _ Path = SourcePath{}
    478 
    479 func (p SourcePath) withRel(rel string) SourcePath {
    480 	p.basePath = p.basePath.withRel(rel)
    481 	return p
    482 }
    483 
    484 // safePathForSource is for paths that we expect are safe -- only for use by go
    485 // code that is embedding ninja variables in paths
    486 func safePathForSource(ctx PathContext, path string) SourcePath {
    487 	p, err := validateSafePath(path)
    488 	if err != nil {
    489 		reportPathError(ctx, err)
    490 	}
    491 	ret := SourcePath{basePath{p, ctx.Config(), ""}}
    492 
    493 	abs, err := filepath.Abs(ret.String())
    494 	if err != nil {
    495 		reportPathError(ctx, err)
    496 		return ret
    497 	}
    498 	buildroot, err := filepath.Abs(ctx.Config().buildDir)
    499 	if err != nil {
    500 		reportPathError(ctx, err)
    501 		return ret
    502 	}
    503 	if strings.HasPrefix(abs, buildroot) {
    504 		reportPathErrorf(ctx, "source path %s is in output", abs)
    505 		return ret
    506 	}
    507 
    508 	return ret
    509 }
    510 
    511 // pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
    512 func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
    513 	p, err := validatePath(pathComponents...)
    514 	ret := SourcePath{basePath{p, ctx.Config(), ""}}
    515 	if err != nil {
    516 		return ret, err
    517 	}
    518 
    519 	abs, err := filepath.Abs(ret.String())
    520 	if err != nil {
    521 		return ret, err
    522 	}
    523 	buildroot, err := filepath.Abs(ctx.Config().buildDir)
    524 	if err != nil {
    525 		return ret, err
    526 	}
    527 	if strings.HasPrefix(abs, buildroot) {
    528 		return ret, fmt.Errorf("source path %s is in output", abs)
    529 	}
    530 
    531 	if pathtools.IsGlob(ret.String()) {
    532 		return ret, fmt.Errorf("path may not contain a glob: %s", ret.String())
    533 	}
    534 
    535 	return ret, nil
    536 }
    537 
    538 // existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
    539 // path does not exist.
    540 func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
    541 	var files []string
    542 
    543 	if gctx, ok := ctx.(PathGlobContext); ok {
    544 		// Use glob to produce proper dependencies, even though we only want
    545 		// a single file.
    546 		files, err = gctx.GlobWithDeps(path.String(), nil)
    547 	} else {
    548 		var deps []string
    549 		// We cannot add build statements in this context, so we fall back to
    550 		// AddNinjaFileDeps
    551 		files, deps, err = pathtools.Glob(path.String(), nil)
    552 		ctx.AddNinjaFileDeps(deps...)
    553 	}
    554 
    555 	if err != nil {
    556 		return false, fmt.Errorf("glob: %s", err.Error())
    557 	}
    558 
    559 	return len(files) > 0, nil
    560 }
    561 
    562 // PathForSource joins the provided path components and validates that the result
    563 // neither escapes the source dir nor is in the out dir.
    564 // On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
    565 func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
    566 	path, err := pathForSource(ctx, pathComponents...)
    567 	if err != nil {
    568 		reportPathError(ctx, err)
    569 	}
    570 
    571 	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
    572 		exists, err := existsWithDependencies(ctx, path)
    573 		if err != nil {
    574 			reportPathError(ctx, err)
    575 		}
    576 		if !exists {
    577 			modCtx.AddMissingDependencies([]string{path.String()})
    578 		}
    579 	} else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
    580 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
    581 	} else if !exists {
    582 		reportPathErrorf(ctx, "source path %s does not exist", path)
    583 	}
    584 	return path
    585 }
    586 
    587 // ExistentPathForSource returns an OptionalPath with the SourcePath if the
    588 // path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
    589 // so that the ninja file will be regenerated if the state of the path changes.
    590 func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
    591 	path, err := pathForSource(ctx, pathComponents...)
    592 	if err != nil {
    593 		reportPathError(ctx, err)
    594 		return OptionalPath{}
    595 	}
    596 
    597 	exists, err := existsWithDependencies(ctx, path)
    598 	if err != nil {
    599 		reportPathError(ctx, err)
    600 		return OptionalPath{}
    601 	}
    602 	if !exists {
    603 		return OptionalPath{}
    604 	}
    605 	return OptionalPathForPath(path)
    606 }
    607 
    608 func (p SourcePath) String() string {
    609 	return filepath.Join(p.config.srcDir, p.path)
    610 }
    611 
    612 // Join creates a new SourcePath with paths... joined with the current path. The
    613 // provided paths... may not use '..' to escape from the current path.
    614 func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
    615 	path, err := validatePath(paths...)
    616 	if err != nil {
    617 		reportPathError(ctx, err)
    618 	}
    619 	return p.withRel(path)
    620 }
    621 
    622 // OverlayPath returns the overlay for `path' if it exists. This assumes that the
    623 // SourcePath is the path to a resource overlay directory.
    624 func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath {
    625 	var relDir string
    626 	if moduleSrcPath, ok := path.(ModuleSrcPath); ok {
    627 		relDir = moduleSrcPath.path
    628 	} else if srcPath, ok := path.(SourcePath); ok {
    629 		relDir = srcPath.path
    630 	} else {
    631 		reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
    632 		return OptionalPath{}
    633 	}
    634 	dir := filepath.Join(p.config.srcDir, p.path, relDir)
    635 	// Use Glob so that we are run again if the directory is added.
    636 	if pathtools.IsGlob(dir) {
    637 		reportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
    638 	}
    639 	paths, err := ctx.GlobWithDeps(dir, nil)
    640 	if err != nil {
    641 		reportPathErrorf(ctx, "glob: %s", err.Error())
    642 		return OptionalPath{}
    643 	}
    644 	if len(paths) == 0 {
    645 		return OptionalPath{}
    646 	}
    647 	relPath, err := filepath.Rel(p.config.srcDir, paths[0])
    648 	if err != nil {
    649 		reportPathError(ctx, err)
    650 		return OptionalPath{}
    651 	}
    652 	return OptionalPathForPath(PathForSource(ctx, relPath))
    653 }
    654 
    655 // OutputPath is a Path representing a file path rooted from the build directory
    656 type OutputPath struct {
    657 	basePath
    658 }
    659 
    660 func (p OutputPath) withRel(rel string) OutputPath {
    661 	p.basePath = p.basePath.withRel(rel)
    662 	return p
    663 }
    664 
    665 var _ Path = OutputPath{}
    666 
    667 // PathForOutput joins the provided paths and returns an OutputPath that is
    668 // validated to not escape the build dir.
    669 // On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
    670 func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
    671 	path, err := validatePath(pathComponents...)
    672 	if err != nil {
    673 		reportPathError(ctx, err)
    674 	}
    675 	return OutputPath{basePath{path, ctx.Config(), ""}}
    676 }
    677 
    678 func (p OutputPath) writablePath() {}
    679 
    680 func (p OutputPath) String() string {
    681 	return filepath.Join(p.config.buildDir, p.path)
    682 }
    683 
    684 func (p OutputPath) RelPathString() string {
    685 	return p.path
    686 }
    687 
    688 // Join creates a new OutputPath with paths... joined with the current path. The
    689 // provided paths... may not use '..' to escape from the current path.
    690 func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
    691 	path, err := validatePath(paths...)
    692 	if err != nil {
    693 		reportPathError(ctx, err)
    694 	}
    695 	return p.withRel(path)
    696 }
    697 
    698 // PathForIntermediates returns an OutputPath representing the top-level
    699 // intermediates directory.
    700 func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
    701 	path, err := validatePath(paths...)
    702 	if err != nil {
    703 		reportPathError(ctx, err)
    704 	}
    705 	return PathForOutput(ctx, ".intermediates", path)
    706 }
    707 
    708 // DistPath is a Path representing a file path rooted from the dist directory
    709 type DistPath struct {
    710 	basePath
    711 }
    712 
    713 func (p DistPath) withRel(rel string) DistPath {
    714 	p.basePath = p.basePath.withRel(rel)
    715 	return p
    716 }
    717 
    718 var _ Path = DistPath{}
    719 
    720 // PathForDist joins the provided paths and returns a DistPath that is
    721 // validated to not escape the dist dir.
    722 // On error, it will return a usable, but invalid DistPath, and report a ModuleError.
    723 func PathForDist(ctx PathContext, pathComponents ...string) DistPath {
    724 	path, err := validatePath(pathComponents...)
    725 	if err != nil {
    726 		reportPathError(ctx, err)
    727 	}
    728 	return DistPath{basePath{path, ctx.Config(), ""}}
    729 }
    730 
    731 func (p DistPath) writablePath() {}
    732 
    733 func (p DistPath) Valid() bool {
    734 	return p.config.productVariables.DistDir != nil && *p.config.productVariables.DistDir != ""
    735 }
    736 
    737 func (p DistPath) String() string {
    738 	if !p.Valid() {
    739 		panic("Requesting an invalid path")
    740 	}
    741 	return filepath.Join(*p.config.productVariables.DistDir, p.path)
    742 }
    743 
    744 func (p DistPath) RelPathString() string {
    745 	return p.path
    746 }
    747 
    748 // ModuleSrcPath is a Path representing a file rooted from a module's local source dir
    749 type ModuleSrcPath struct {
    750 	SourcePath
    751 }
    752 
    753 var _ Path = ModuleSrcPath{}
    754 var _ genPathProvider = ModuleSrcPath{}
    755 var _ objPathProvider = ModuleSrcPath{}
    756 var _ resPathProvider = ModuleSrcPath{}
    757 
    758 // PathForModuleSrc returns a ModuleSrcPath representing the paths... under the
    759 // module's local source directory.
    760 func PathForModuleSrc(ctx ModuleContext, paths ...string) ModuleSrcPath {
    761 	p, err := validatePath(paths...)
    762 	if err != nil {
    763 		reportPathError(ctx, err)
    764 	}
    765 
    766 	srcPath, err := pathForSource(ctx, ctx.ModuleDir(), p)
    767 	if err != nil {
    768 		reportPathError(ctx, err)
    769 	}
    770 
    771 	path := ModuleSrcPath{srcPath}
    772 	path.basePath.rel = p
    773 
    774 	if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
    775 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
    776 	} else if !exists {
    777 		reportPathErrorf(ctx, "module source path %s does not exist", path)
    778 	}
    779 
    780 	return path
    781 }
    782 
    783 // OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
    784 // valid path if p is non-nil.
    785 func OptionalPathForModuleSrc(ctx ModuleContext, p *string) OptionalPath {
    786 	if p == nil {
    787 		return OptionalPath{}
    788 	}
    789 	return OptionalPathForPath(PathForModuleSrc(ctx, *p))
    790 }
    791 
    792 func (p ModuleSrcPath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
    793 	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
    794 }
    795 
    796 func (p ModuleSrcPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
    797 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
    798 }
    799 
    800 func (p ModuleSrcPath) resPathWithName(ctx ModuleContext, name string) ModuleResPath {
    801 	// TODO: Use full directory if the new ctx is not the current ctx?
    802 	return PathForModuleRes(ctx, p.path, name)
    803 }
    804 
    805 func (p ModuleSrcPath) WithSubDir(ctx ModuleContext, subdir string) ModuleSrcPath {
    806 	subdir = PathForModuleSrc(ctx, subdir).String()
    807 	var err error
    808 	rel, err := filepath.Rel(subdir, p.path)
    809 	if err != nil {
    810 		ctx.ModuleErrorf("source file %q is not under path %q", p.path, subdir)
    811 		return p
    812 	}
    813 	p.rel = rel
    814 	return p
    815 }
    816 
    817 // ModuleOutPath is a Path representing a module's output directory.
    818 type ModuleOutPath struct {
    819 	OutputPath
    820 }
    821 
    822 var _ Path = ModuleOutPath{}
    823 
    824 func pathForModule(ctx ModuleContext) OutputPath {
    825 	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
    826 }
    827 
    828 // PathForVndkRefDump returns an OptionalPath representing the path of the reference
    829 // abi dump for the given module. This is not guaranteed to be valid.
    830 func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string, vndkOrNdk, isSourceDump bool) OptionalPath {
    831 	arches := ctx.DeviceConfig().Arches()
    832 	currentArch := ctx.Arch()
    833 	archNameAndVariant := currentArch.ArchType.String()
    834 	if currentArch.ArchVariant != "" {
    835 		archNameAndVariant += "_" + currentArch.ArchVariant
    836 	}
    837 	var sourceOrBinaryDir string
    838 	var vndkOrNdkDir string
    839 	var ext string
    840 	if isSourceDump {
    841 		ext = ".lsdump.gz"
    842 		sourceOrBinaryDir = "source-based"
    843 	} else {
    844 		ext = ".bdump.gz"
    845 		sourceOrBinaryDir = "binary-based"
    846 	}
    847 	if vndkOrNdk {
    848 		vndkOrNdkDir = "vndk"
    849 	} else {
    850 		vndkOrNdkDir = "ndk"
    851 	}
    852 	if len(arches) == 0 {
    853 		panic("device build with no primary arch")
    854 	}
    855 	binderBitness := ctx.DeviceConfig().BinderBitness()
    856 	refDumpFileStr := "prebuilts/abi-dumps/" + vndkOrNdkDir + "/" + version + "/" + binderBitness + "/" +
    857 		archNameAndVariant + "/" + sourceOrBinaryDir + "/" + fileName + ext
    858 	return ExistentPathForSource(ctx, refDumpFileStr)
    859 }
    860 
    861 // PathForModuleOut returns a Path representing the paths... under the module's
    862 // output directory.
    863 func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
    864 	p, err := validatePath(paths...)
    865 	if err != nil {
    866 		reportPathError(ctx, err)
    867 	}
    868 	return ModuleOutPath{
    869 		OutputPath: pathForModule(ctx).withRel(p),
    870 	}
    871 }
    872 
    873 // ModuleGenPath is a Path representing the 'gen' directory in a module's output
    874 // directory. Mainly used for generated sources.
    875 type ModuleGenPath struct {
    876 	ModuleOutPath
    877 }
    878 
    879 var _ Path = ModuleGenPath{}
    880 var _ genPathProvider = ModuleGenPath{}
    881 var _ objPathProvider = ModuleGenPath{}
    882 
    883 // PathForModuleGen returns a Path representing the paths... under the module's
    884 // `gen' directory.
    885 func PathForModuleGen(ctx ModuleContext, paths ...string) ModuleGenPath {
    886 	p, err := validatePath(paths...)
    887 	if err != nil {
    888 		reportPathError(ctx, err)
    889 	}
    890 	return ModuleGenPath{
    891 		ModuleOutPath: ModuleOutPath{
    892 			OutputPath: pathForModule(ctx).withRel("gen").withRel(p),
    893 		},
    894 	}
    895 }
    896 
    897 func (p ModuleGenPath) genPathWithExt(ctx ModuleContext, subdir, ext string) ModuleGenPath {
    898 	// TODO: make a different path for local vs remote generated files?
    899 	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
    900 }
    901 
    902 func (p ModuleGenPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
    903 	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
    904 }
    905 
    906 // ModuleObjPath is a Path representing the 'obj' directory in a module's output
    907 // directory. Used for compiled objects.
    908 type ModuleObjPath struct {
    909 	ModuleOutPath
    910 }
    911 
    912 var _ Path = ModuleObjPath{}
    913 
    914 // PathForModuleObj returns a Path representing the paths... under the module's
    915 // 'obj' directory.
    916 func PathForModuleObj(ctx ModuleContext, pathComponents ...string) ModuleObjPath {
    917 	p, err := validatePath(pathComponents...)
    918 	if err != nil {
    919 		reportPathError(ctx, err)
    920 	}
    921 	return ModuleObjPath{PathForModuleOut(ctx, "obj", p)}
    922 }
    923 
    924 // ModuleResPath is a a Path representing the 'res' directory in a module's
    925 // output directory.
    926 type ModuleResPath struct {
    927 	ModuleOutPath
    928 }
    929 
    930 var _ Path = ModuleResPath{}
    931 
    932 // PathForModuleRes returns a Path representing the paths... under the module's
    933 // 'res' directory.
    934 func PathForModuleRes(ctx ModuleContext, pathComponents ...string) ModuleResPath {
    935 	p, err := validatePath(pathComponents...)
    936 	if err != nil {
    937 		reportPathError(ctx, err)
    938 	}
    939 
    940 	return ModuleResPath{PathForModuleOut(ctx, "res", p)}
    941 }
    942 
    943 // PathForModuleInstall returns a Path representing the install path for the
    944 // module appended with paths...
    945 func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) OutputPath {
    946 	var outPaths []string
    947 	if ctx.Device() {
    948 		var partition string
    949 		if ctx.InstallInData() {
    950 			partition = "data"
    951 		} else if ctx.SocSpecific() {
    952 			partition = ctx.DeviceConfig().VendorPath()
    953 		} else if ctx.DeviceSpecific() {
    954 			partition = ctx.DeviceConfig().OdmPath()
    955 		} else if ctx.ProductSpecific() {
    956 			partition = ctx.DeviceConfig().ProductPath()
    957 		} else {
    958 			partition = "system"
    959 		}
    960 
    961 		if ctx.InstallInSanitizerDir() {
    962 			partition = "data/asan/" + partition
    963 		}
    964 		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
    965 	} else {
    966 		switch ctx.Os() {
    967 		case Linux:
    968 			outPaths = []string{"host", "linux-x86"}
    969 		case LinuxBionic:
    970 			// TODO: should this be a separate top level, or shared with linux-x86?
    971 			outPaths = []string{"host", "linux_bionic-x86"}
    972 		default:
    973 			outPaths = []string{"host", ctx.Os().String() + "-x86"}
    974 		}
    975 	}
    976 	if ctx.Debug() {
    977 		outPaths = append([]string{"debug"}, outPaths...)
    978 	}
    979 	outPaths = append(outPaths, pathComponents...)
    980 	return PathForOutput(ctx, outPaths...)
    981 }
    982 
    983 // validateSafePath validates a path that we trust (may contain ninja variables).
    984 // Ensures that each path component does not attempt to leave its component.
    985 func validateSafePath(pathComponents ...string) (string, error) {
    986 	for _, path := range pathComponents {
    987 		path := filepath.Clean(path)
    988 		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
    989 			return "", fmt.Errorf("Path is outside directory: %s", path)
    990 		}
    991 	}
    992 	// TODO: filepath.Join isn't necessarily correct with embedded ninja
    993 	// variables. '..' may remove the entire ninja variable, even if it
    994 	// will be expanded to multiple nested directories.
    995 	return filepath.Join(pathComponents...), nil
    996 }
    997 
    998 // validatePath validates that a path does not include ninja variables, and that
    999 // each path component does not attempt to leave its component. Returns a joined
   1000 // version of each path component.
   1001 func validatePath(pathComponents ...string) (string, error) {
   1002 	for _, path := range pathComponents {
   1003 		if strings.Contains(path, "$") {
   1004 			return "", fmt.Errorf("Path contains invalid character($): %s", path)
   1005 		}
   1006 	}
   1007 	return validateSafePath(pathComponents...)
   1008 }
   1009 
   1010 func PathForPhony(ctx PathContext, phony string) WritablePath {
   1011 	if strings.ContainsAny(phony, "$/") {
   1012 		reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
   1013 	}
   1014 	return PhonyPath{basePath{phony, ctx.Config(), ""}}
   1015 }
   1016 
   1017 type PhonyPath struct {
   1018 	basePath
   1019 }
   1020 
   1021 func (p PhonyPath) writablePath() {}
   1022 
   1023 var _ Path = PhonyPath{}
   1024 var _ WritablePath = PhonyPath{}
   1025 
   1026 type testPath struct {
   1027 	basePath
   1028 }
   1029 
   1030 func (p testPath) String() string {
   1031 	return p.path
   1032 }
   1033 
   1034 func PathForTesting(paths ...string) Path {
   1035 	p, err := validateSafePath(paths...)
   1036 	if err != nil {
   1037 		panic(err)
   1038 	}
   1039 	return testPath{basePath{path: p, rel: p}}
   1040 }
   1041 
   1042 func PathsForTesting(strs []string) Paths {
   1043 	p := make(Paths, len(strs))
   1044 	for i, s := range strs {
   1045 		p[i] = PathForTesting(s)
   1046 	}
   1047 
   1048 	return p
   1049 }
   1050