1// Copyright 2017 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 build 16 17import ( 18 "android/soong/finder" 19 "android/soong/finder/fs" 20 "android/soong/ui/logger" 21 "bytes" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "strings" 26 27 "android/soong/ui/metrics" 28) 29 30// This file provides an interface to the Finder for use in Soong UI 31// This file stores configuration information about which files to find 32 33// NewSourceFinder returns a new Finder configured to search for source files. 34// Callers of NewSourceFinder should call <f.Shutdown()> when done 35func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { 36 ctx.BeginTrace(metrics.RunSetupTool, "find modules") 37 defer ctx.EndTrace() 38 39 dir, err := os.Getwd() 40 if err != nil { 41 ctx.Fatalf("No working directory for module-finder: %v", err.Error()) 42 } 43 filesystem := fs.OsFs 44 45 // if the root dir is ignored, then the subsequent error messages are very confusing, 46 // so check for that upfront 47 pruneFiles := []string{".out-dir", ".find-ignore"} 48 for _, name := range pruneFiles { 49 prunePath := filepath.Join(dir, name) 50 _, statErr := filesystem.Lstat(prunePath) 51 if statErr == nil { 52 ctx.Fatalf("%v must not exist", prunePath) 53 } 54 } 55 56 cacheParams := finder.CacheParams{ 57 WorkingDirectory: dir, 58 RootDirs: []string{"."}, 59 ExcludeDirs: []string{".git", ".repo"}, 60 PruneFiles: pruneFiles, 61 IncludeFiles: []string{ 62 "Android.mk", 63 "AndroidProducts.mk", 64 "Android.bp", 65 "Blueprints", 66 "CleanSpec.mk", 67 "OWNERS", 68 "TEST_MAPPING", 69 }, 70 } 71 dumpDir := config.FileListDir() 72 f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard), 73 filepath.Join(dumpDir, "files.db")) 74 if err != nil { 75 ctx.Fatalf("Could not create module-finder: %v", err) 76 } 77 return f 78} 79 80// FindSources searches for source files known to <f> and writes them to the filesystem for 81// use later. 82func FindSources(ctx Context, config Config, f *finder.Finder) { 83 // note that dumpDir in FindSources may be different than dumpDir in NewSourceFinder 84 // if a caller such as multiproduct_kati wants to share one Finder among several builds 85 dumpDir := config.FileListDir() 86 os.MkdirAll(dumpDir, 0777) 87 88 androidMks := f.FindFirstNamedAt(".", "Android.mk") 89 err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list")) 90 if err != nil { 91 ctx.Fatalf("Could not export module list: %v", err) 92 } 93 94 androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk") 95 androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...) 96 androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...) 97 err = dumpListToFile(ctx, config, androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list")) 98 if err != nil { 99 ctx.Fatalf("Could not export product list: %v", err) 100 } 101 102 cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk") 103 err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list")) 104 if err != nil { 105 ctx.Fatalf("Could not export module list: %v", err) 106 } 107 108 owners := f.FindNamedAt(".", "OWNERS") 109 err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list")) 110 if err != nil { 111 ctx.Fatalf("Could not find OWNERS: %v", err) 112 } 113 114 testMappings := f.FindNamedAt(".", "TEST_MAPPING") 115 err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list")) 116 if err != nil { 117 ctx.Fatalf("Could not find TEST_MAPPING: %v", err) 118 } 119 120 androidBps := f.FindNamedAt(".", "Android.bp") 121 androidBps = append(androidBps, f.FindNamedAt("build/blueprint", "Blueprints")...) 122 if len(androidBps) == 0 { 123 ctx.Fatalf("No Android.bp found") 124 } 125 err = dumpListToFile(ctx, config, androidBps, filepath.Join(dumpDir, "Android.bp.list")) 126 if err != nil { 127 ctx.Fatalf("Could not find modules: %v", err) 128 } 129 130 if config.Dist() { 131 f.WaitForDbDump() 132 distFile(ctx, config, f.DbPath, "module_paths") 133 } 134} 135 136func dumpListToFile(ctx Context, config Config, list []string, filePath string) (err error) { 137 desiredText := strings.Join(list, "\n") 138 desiredBytes := []byte(desiredText) 139 actualBytes, readErr := ioutil.ReadFile(filePath) 140 if readErr != nil || !bytes.Equal(desiredBytes, actualBytes) { 141 err = ioutil.WriteFile(filePath, desiredBytes, 0777) 142 if err != nil { 143 return err 144 } 145 } 146 147 distFile(ctx, config, filePath, "module_paths") 148 149 return nil 150} 151