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 main 16 17import ( 18 "errors" 19 "flag" 20 "fmt" 21 "io" 22 "io/ioutil" 23 "log" 24 "os" 25 "runtime/pprof" 26 "sort" 27 "strings" 28 "time" 29 30 "android/soong/finder" 31 "android/soong/finder/fs" 32) 33 34var ( 35 // configuration of what to find 36 excludeDirs string 37 filenamesToFind string 38 pruneFiles string 39 40 // other configuration 41 cpuprofile string 42 verbose bool 43 dbPath string 44 numIterations int 45) 46 47func init() { 48 flag.StringVar(&cpuprofile, "cpuprofile", "", 49 "filepath of profile file to write (optional)") 50 flag.BoolVar(&verbose, "v", false, "log additional information") 51 flag.StringVar(&dbPath, "db", "", "filepath of cache db") 52 53 flag.StringVar(&excludeDirs, "exclude-dirs", "", 54 "comma-separated list of directory names to exclude from search") 55 flag.StringVar(&filenamesToFind, "names", "", 56 "comma-separated list of filenames to find") 57 flag.StringVar(&pruneFiles, "prune-files", "", 58 "filenames that if discovered will exclude their entire directory "+ 59 "(including sibling files and directories)") 60 flag.IntVar(&numIterations, "count", 1, 61 "number of times to run. This is intended for use with --cpuprofile"+ 62 " , to increase profile accuracy") 63} 64 65var usage = func() { 66 fmt.Printf("usage: finder -name <fileName> --db <dbPath> <searchDirectory> [<searchDirectory>...]\n") 67 flag.PrintDefaults() 68} 69 70func main() { 71 err := run() 72 if err != nil { 73 fmt.Fprintf(os.Stderr, "%v\n", err.Error()) 74 os.Exit(1) 75 } 76} 77 78func stringToList(input string) []string { 79 return strings.Split(input, ",") 80} 81 82func run() error { 83 startTime := time.Now() 84 flag.Parse() 85 86 if cpuprofile != "" { 87 f, err := os.Create(cpuprofile) 88 if err != nil { 89 return fmt.Errorf("Error opening cpuprofile: %s", err) 90 } 91 pprof.StartCPUProfile(f) 92 defer f.Close() 93 defer pprof.StopCPUProfile() 94 } 95 96 var writer io.Writer 97 if verbose { 98 writer = os.Stderr 99 } else { 100 writer = ioutil.Discard 101 } 102 103 // TODO: replace Lshortfile with Llongfile when bug 63821638 is done 104 logger := log.New(writer, "", log.Ldate|log.Lmicroseconds|log.Lshortfile) 105 106 logger.Printf("Finder starting at %v\n", startTime) 107 108 rootPaths := flag.Args() 109 if len(rootPaths) < 1 { 110 usage() 111 return fmt.Errorf( 112 "Must give at least one <searchDirectory>") 113 } 114 115 workingDir, err := os.Getwd() 116 if err != nil { 117 return err 118 } 119 params := finder.CacheParams{ 120 WorkingDirectory: workingDir, 121 RootDirs: rootPaths, 122 ExcludeDirs: stringToList(excludeDirs), 123 PruneFiles: stringToList(pruneFiles), 124 IncludeFiles: stringToList(filenamesToFind), 125 } 126 if dbPath == "" { 127 usage() 128 return errors.New("Param 'db' must be nonempty") 129 } 130 131 matches := []string{} 132 for i := 0; i < numIterations; i++ { 133 matches, err = runFind(params, logger) 134 if err != nil { 135 return err 136 } 137 } 138 findDuration := time.Since(startTime) 139 logger.Printf("Found these %v inodes in %v :\n", len(matches), findDuration) 140 sort.Strings(matches) 141 for _, match := range matches { 142 fmt.Println(match) 143 } 144 logger.Printf("End of %v inodes\n", len(matches)) 145 logger.Printf("Finder completed in %v\n", time.Since(startTime)) 146 return nil 147} 148 149func runFind(params finder.CacheParams, logger *log.Logger) (paths []string, err error) { 150 service, err := finder.New(params, fs.OsFs, logger, dbPath) 151 if err != nil { 152 return []string{}, err 153 } 154 defer service.Shutdown() 155 return service.FindAll(), nil 156} 157