blob: eb7c2c0075aef04538112b1ab70c17ded00e66c7 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// 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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090016
17import (
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +090018 "errors"
19 "fmt"
Fumitoshi Ukai106fb792015-06-09 10:37:35 +090020 "os"
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090021 "os/exec"
22 "path/filepath"
Fumitoshi Ukai83410132015-06-15 14:50:07 +090023 "runtime"
Fumitoshi Ukai106fb792015-06-09 10:37:35 +090024 "sort"
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090025 "strings"
Fumitoshi Ukai106fb792015-06-09 10:37:35 +090026 "sync"
27 "time"
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090028)
29
Fumitoshi Ukai9042b992015-06-23 16:10:27 +090030type wildcardCacheT struct {
31 mu sync.Mutex
32 m map[string][]string
33}
34
35var wildcardCache = &wildcardCacheT{
36 m: make(map[string][]string),
37}
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090038
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090039func wildcardGlob(pat string) ([]string, error) {
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090040 // TODO(ukai): use find cache for glob if exists.
41 pattern := filepath.Clean(pat)
42 if pattern != pat {
43 // For some reason, go's Glob normalizes
44 // foo/../bar to bar.
45 i := strings.IndexAny(pattern, "*?[")
46 if i < 0 {
47 // no wildcard. if any files matched with pattern,
48 // return pat.
49 _, err := os.Stat(pat)
50 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090051 return nil, nil
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090052 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090053 return []string{pat}, nil
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090054 }
55 if strings.Contains(pattern[i+1:], "..") {
56 // We ask shell to expand a glob to avoid this.
57 cmdline := []string{"/bin/sh", "-c", "/bin/ls -d " + pat}
58 cmd := exec.Cmd{
59 Path: cmdline[0],
60 Args: cmdline,
61 }
62 // Ignore errors.
63 out, _ := cmd.Output()
64 ws := newWordScanner(out)
65 var files []string
66 for ws.Scan() {
67 files = append(files, string(ws.Bytes()))
68 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090069 return files, nil
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090070 }
71 // prefix + meta + suffix, and suffix doesn't have '..'
72 prefix := pattern[:i]
73 i = strings.IndexAny(pat, "*?[")
74 if i < 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090075 return nil, fmt.Errorf("wildcard metachar mismatch? pattern=%q pat=%q", pattern, pat)
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090076 }
77 oprefix := pat[:i]
78 matched, err := filepath.Glob(pattern)
79 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090080 return nil, err
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090081 }
82 var files []string
83 for _, m := range matched {
84 file := oprefix + strings.TrimPrefix(m, prefix)
85 _, err := os.Stat(file)
86 if err != nil {
87 continue
88 }
89 files = append(files, file)
90 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090091 return files, nil
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090092 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090093 return filepath.Glob(pat)
Fumitoshi Ukai9d959c32015-06-19 18:06:01 +090094}
95
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090096func wildcard(sw *ssvWriter, pat string) error {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090097 if UseWildcardCache {
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +090098 // TODO(ukai): make sure it didn't chdir?
Fumitoshi Ukai9042b992015-06-23 16:10:27 +090099 wildcardCache.mu.Lock()
100 files, ok := wildcardCache.m[pat]
101 wildcardCache.mu.Unlock()
102 if ok {
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900103 for _, file := range files {
104 sw.WriteString(file)
105 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900106 return nil
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900107 }
108 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900109 files, err := wildcardGlob(pat)
110 if err != nil {
111 return err
112 }
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900113 for _, file := range files {
114 sw.WriteString(file)
115 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900116 if UseWildcardCache {
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900117 wildcardCache.mu.Lock()
118 wildcardCache.m[pat] = files
119 wildcardCache.mu.Unlock()
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900120 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900121 return nil
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900122}
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900123
124type fileInfo struct {
125 path string
126 mode os.FileMode
127}
128
129type androidFindCacheT struct {
130 once sync.Once
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900131 filesch chan []fileInfo
132 leavesch chan []fileInfo
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900133 files []fileInfo
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900134 leaves []fileInfo
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900135 scanTime time.Duration
136}
137
138var (
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900139 androidFindCache androidFindCacheT
140 androidDefaultLeafNames = []string{"CleanSpec.mk", "Android.mk"}
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900141)
142
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900143// AndroidFindCacheInit initializes find cache for android build.
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900144func AndroidFindCacheInit(prunes, leafNames []string) {
145 if leafNames != nil {
146 androidDefaultLeafNames = leafNames
147 }
148 androidFindCache.init(prunes)
149}
150
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900151func (c *androidFindCacheT) ready() bool {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900152 if c.files != nil {
153 return true
154 }
155 select {
156 case c.files = <-c.filesch:
157 }
158 return c.files != nil
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900159}
160
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900161func (c *androidFindCacheT) leavesReady() bool {
162 if c.leaves != nil {
163 return true
164 }
165 select {
166 case c.leaves = <-c.leavesch:
167 }
168 return c.leaves != nil
169}
170
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900171func (c *androidFindCacheT) init(prunes []string) {
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900172 c.once.Do(func() {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900173 c.filesch = make(chan []fileInfo, 1)
174 c.leavesch = make(chan []fileInfo, 1)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900175 go c.start(prunes, androidDefaultLeafNames)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900176 })
177}
178
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900179func (c *androidFindCacheT) start(prunes, leafNames []string) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900180 logf("find cache init: prunes=%q leafNames=%q", prunes, leafNames)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900181 te := traceEvent.begin("findcache", literal("init"), traceEventFindCache)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900182 defer func() {
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900183 traceEvent.end(te)
184 c.scanTime = time.Since(te.t)
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900185 logStats("android find cache scan: %v", c.scanTime)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900186 }()
187
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900188 dirs := make(chan string, 32)
189 filech := make(chan fileInfo, 1000)
190 leafch := make(chan fileInfo, 1000)
191 var wg sync.WaitGroup
192 numWorker := runtime.NumCPU() - 1
193 wg.Add(numWorker)
194 for i := 0; i < numWorker; i++ {
195 go func() {
196 defer wg.Done()
197 for dir := range dirs {
198 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
199 if info.IsDir() {
200 for _, prune := range prunes {
201 if info.Name() == prune {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900202 logf("find cache prune: %s", path)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900203 return filepath.SkipDir
204 }
205 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900206 }
207 filech <- fileInfo{
208 path: path,
209 mode: info.Mode(),
210 }
211 for _, leaf := range leafNames {
212 if info.Name() == leaf {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900213 logf("find cache leaf: %s", path)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900214 leafch <- fileInfo{
215 path: path,
216 mode: info.Mode(),
217 }
218 break
219 }
220 }
221 return nil
222 })
223 if err != nil && err != filepath.SkipDir {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900224 logf("error in adnroid find cache: %v", err)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900225 close(c.filesch)
226 close(c.leavesch)
227 return
Fumitoshi Ukai0daac1f2015-06-11 11:56:50 +0900228 }
229 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900230 }()
231 }
232
233 go func() {
Fumitoshi Ukai040271f2015-06-18 11:04:46 +0900234 dirs := make(map[string]bool)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900235 leavesTe := traceEvent.begin("findcache", literal("leaves"), traceEventFindCacheLeaves)
236 var leaves []fileInfo
Fumitoshi Ukai040271f2015-06-18 11:04:46 +0900237 nfiles := 0
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900238 for leaf := range leafch {
239 leaves = append(leaves, leaf)
Fumitoshi Ukai040271f2015-06-18 11:04:46 +0900240 nfiles++
241 for dir := filepath.Dir(leaf.path); dir != "."; dir = filepath.Dir(dir) {
242 if dirs[dir] {
243 break
244 }
245 leaves = append(leaves, fileInfo{
246 path: dir,
247 mode: leaf.mode | os.ModeDir,
248 })
249 dirs[dir] = true
250 }
Fumitoshi Ukai0daac1f2015-06-11 11:56:50 +0900251 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900252 sort.Sort(fileInfoByLeaf(leaves))
253 c.leavesch <- leaves
254 traceEvent.end(leavesTe)
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900255 logStats("%d leaves %d dirs in find cache", nfiles, len(dirs))
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900256 for i, leaf := range leaves {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900257 logf("android findleaves cache: %d: %s %v", i, leaf.path, leaf.mode)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900258 }
259 }()
260
261 go func() {
262 filesTe := traceEvent.begin("findcache", literal("files"), traceEventFindCacheFiles)
263 var files []fileInfo
264 for file := range filech {
265 files = append(files, file)
266 }
267 sort.Sort(fileInfoByName(files))
268 c.filesch <- files
269 traceEvent.end(filesTe)
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900270 logStats("%d files in find cache", len(files))
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900271 for i, fi := range files {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900272 logf("android find cache: %d: %s %v", i, fi.path, fi.mode)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900273 }
274 }()
275
276 curdir, err := os.Open(".")
277 if err != nil {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900278 logf("open . failed: %v", err)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900279 close(c.filesch)
280 close(c.leavesch)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900281 return
282 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900283 names, err := curdir.Readdirnames(-1)
284 if err != nil {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900285 logf("readdir . failed: %v", err)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900286 close(c.filesch)
287 close(c.leavesch)
288 return
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900289 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900290 curdir.Close()
291
292 for _, name := range names {
293 dirs <- name
294 }
295 close(dirs)
296 wg.Wait()
297 close(filech)
298 close(leafch)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900299}
300
301type fileInfoByName []fileInfo
302
303func (f fileInfoByName) Len() int { return len(f) }
304func (f fileInfoByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
305func (f fileInfoByName) Less(i, j int) bool {
306 return f[i].path < f[j].path
307}
308
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900309type fileInfoByLeaf []fileInfo
310
311func (f fileInfoByLeaf) Len() int { return len(f) }
312func (f fileInfoByLeaf) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
313func (f fileInfoByLeaf) Less(i, j int) bool {
314 di := strings.Count(f[i].path, "/")
315 dj := strings.Count(f[j].path, "/")
316 if di != dj {
317 return di < dj
318 }
Fumitoshi Ukaic39b1882015-06-16 16:29:08 +0900319 diri := filepath.Dir(f[i].path) + "/"
320 dirj := filepath.Dir(f[j].path) + "/"
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900321 if diri != dirj {
322 return diri < dirj
323 }
324 mdi := f[i].mode & os.ModeDir
325 mdj := f[j].mode & os.ModeDir
326 if mdi != mdj {
327 return mdi < mdj
328 }
329 return f[i].path < f[j].path
330}
331
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900332var errSkipDir = errors.New("skip dir")
333
334func (c *androidFindCacheT) walk(dir string, walkFn func(int, fileInfo) error) error {
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900335 i := sort.Search(len(c.files), func(i int) bool {
336 return c.files[i].path >= dir
337 })
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900338 logf("android find in dir cache: %s i=%d/%d", dir, i, len(c.files))
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900339 start := i
340 var skipdirs []string
341Loop:
342 for i := start; i < len(c.files); i++ {
343 if c.files[i].path == dir {
344 err := walkFn(i, c.files[i])
345 if err != nil {
346 return err
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900347 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900348 continue
349 }
350 if !strings.HasPrefix(c.files[i].path, dir) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900351 logf("android find in dir cache: %s end=%d/%d", dir, i, len(c.files))
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900352 return nil
353 }
354 if !strings.HasPrefix(c.files[i].path, dir+"/") {
355 continue
356 }
357 for _, skip := range skipdirs {
358 if strings.HasPrefix(c.files[i].path, skip+"/") {
359 continue Loop
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900360 }
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900361 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900362
363 err := walkFn(i, c.files[i])
364 if err == errSkipDir {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900365 logf("android find in skip dir: %s", c.files[i].path)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900366 skipdirs = append(skipdirs, c.files[i].path)
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900367 continue
368 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900369 if err != nil {
370 return err
371 }
372 }
373 return nil
374}
375
376// pattern in repo/android/build/core/definitions.mk
377// find-subdir-assets
378// if [ -d $1 ] ; then cd $1 ; find ./ -not -name '.*' -and -type f -and -not -type l ; fi
379func (c *androidFindCacheT) findInDir(sw *ssvWriter, dir string) {
380 dir = filepath.Clean(dir)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900381 logf("android find in dir cache: %s", dir)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900382 c.walk(dir, func(_ int, fi fileInfo) error {
383 // -not -name '.*'
384 if strings.HasPrefix(filepath.Base(fi.path), ".") {
385 return nil
386 }
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900387 // -type f and -not -type l
388 // regular type and not symlink
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900389 if !fi.mode.IsRegular() {
390 return nil
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900391 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900392 name := strings.TrimPrefix(fi.path, dir+"/")
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900393 name = "./" + name
394 sw.WriteString(name)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900395 logf("android find in dir cache: %s=> %s", dir, name)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900396 return nil
397 })
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900398}
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900399
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900400// pattern in repo/android/build/core/definitions.mk
Fumitoshi Ukaib234e272015-06-18 13:14:16 +0900401// all-java-files-under etc
402// cd ${LOCAL_PATH} ; find -L $1 -name "*<ext>" -and -not -name ".*"
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900403// returns false if symlink is found.
Fumitoshi Ukaib234e272015-06-18 13:14:16 +0900404func (c *androidFindCacheT) findExtFilesUnder(sw *ssvWriter, chdir, root, ext string) bool {
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900405 chdir = filepath.Clean(chdir)
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900406 dir := filepath.Join(chdir, root)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900407 logf("android find %s in dir cache: %s %s", ext, chdir, root)
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900408 // check symlinks
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900409 var matches []int
410 err := c.walk(dir, func(i int, fi fileInfo) error {
411 if fi.mode&os.ModeSymlink == os.ModeSymlink {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900412 logf("android find %s in dir cache: detect symlink %s %v", ext, c.files[i].path, c.files[i].mode)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900413 return fmt.Errorf("symlink %s", fi.path)
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900414 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900415 matches = append(matches, i)
416 return nil
417 })
418 if err != nil {
419 return false
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900420 }
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900421 // no symlinks
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900422 for _, i := range matches {
423 fi := c.files[i]
424 base := filepath.Base(fi.path)
Fumitoshi Ukaib234e272015-06-18 13:14:16 +0900425 // -name "*<ext>"
426 if filepath.Ext(base) != ext {
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900427 continue
428 }
429 // -not -name ".*"
430 if strings.HasPrefix(base, ".") {
431 continue
432 }
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900433 name := strings.TrimPrefix(fi.path, chdir+"/")
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900434 sw.WriteString(name)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900435 logf("android find %s in dir cache: %s=> %s", ext, dir, name)
Fumitoshi Ukai1a77c8c2015-06-09 12:56:22 +0900436 }
437 return true
438}
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900439
440// pattern: in repo/android/build/core/base_rules.mk
441// java_resource_file_groups+= ...
442// cd ${TOP_DIR}${LOCAL_PATH}/${dir} && find . -type d -a -name ".svn" -prune \
443// -o -type f -a \! -name "*.java" -a \! -name "package.html" -a \! \
444// -name "overview.html" -a \! -name ".*.swp" -a \! -name ".DS_Store" \
445// -a \! -name "*~" -print )
446func (c *androidFindCacheT) findJavaResourceFileGroup(sw *ssvWriter, dir string) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900447 logf("android find java resource in dir cache: %s", dir)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900448 c.walk(filepath.Clean(dir), func(_ int, fi fileInfo) error {
449 // -type d -a -name ".svn" -prune
450 if fi.mode.IsDir() && filepath.Base(fi.path) == ".svn" {
451 return errSkipDir
452 }
453 // -type f
454 if !fi.mode.IsRegular() {
455 return nil
456 }
457 // ! -name "*.java" -a ! -name "package.html" -a
458 // ! -name "overview.html" -a ! -name ".*.swp" -a
459 // ! -name ".DS_Store" -a ! -name "*~"
460 base := filepath.Base(fi.path)
461 if filepath.Ext(base) == ".java" ||
462 base == "package.html" ||
463 base == "overview.html" ||
464 (strings.HasPrefix(base, ".") && strings.HasSuffix(base, ".swp")) ||
465 base == ".DS_Store" ||
466 strings.HasSuffix(base, "~") {
467 return nil
468 }
469 name := strings.TrimPrefix(fi.path, dir+"/")
470 name = "./" + name
471 sw.WriteString(name)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900472 logf("android find java resource in dir cache: %s=> %s", dir, name)
Fumitoshi Ukai7adc0f52015-06-09 15:34:26 +0900473 return nil
474 })
475}
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900476
477func (c *androidFindCacheT) findleaves(sw *ssvWriter, dir, name string, prunes []string, mindepth int) bool {
Fumitoshi Ukai40e35f52015-06-16 16:33:04 +0900478 var found []string
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900479 var dirs []string
480 topdepth := 1 + strings.Count(dir, "/")
481 dirs = append(dirs, dir)
482 for len(dirs) > 0 {
483 dir = filepath.Clean(dirs[0]) + "/"
484 dirs = dirs[1:]
485 if dir == "./" {
486 dir = ""
487 }
488 depth := strings.Count(dir, "/")
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900489 // logf("android findleaves dir=%q depth=%d dirs=%q", dir, depth, dirs)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900490 i := sort.Search(len(c.leaves), func(i int) bool {
491 di := strings.Count(c.leaves[i].path, "/")
492 if di != depth {
493 return di >= depth
494 }
Fumitoshi Ukaic39b1882015-06-16 16:29:08 +0900495 diri := filepath.Dir(c.leaves[i].path) + "/"
496 if diri != dir {
497 return diri >= dir
498 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900499 return c.leaves[i].path >= dir
500 })
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900501 logf("android findleaves dir=%q i=%d/%d", dir, i, len(c.leaves))
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900502
503 Scandir:
504 for ; i < len(c.leaves); i++ {
505 if dir == "" && strings.Contains(c.leaves[i].path, "/") {
506 break
507 }
508 if !strings.HasPrefix(c.leaves[i].path, dir) {
509 break
510 }
511 if mindepth < 0 || depth >= topdepth+mindepth {
512 if !c.leaves[i].mode.IsDir() && filepath.Base(c.leaves[i].path) == name {
513 n := "./" + c.leaves[i].path
Fumitoshi Ukai40e35f52015-06-16 16:33:04 +0900514 found = append(found, n)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900515 logf("android findleaves name=%s=> %s (depth=%d topdepth=%d mindepth=%d)", name, n, depth, topdepth, mindepth)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900516 break Scandir
517 }
518 }
519 if c.leaves[i].mode.IsDir() {
520 dirs = append(dirs, c.leaves[i].path)
521 }
522 }
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900523 // logf("android findleaves next dirs=%q", dirs)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900524 }
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900525 logf("android findleave done")
Fumitoshi Ukai40e35f52015-06-16 16:33:04 +0900526 sort.Strings(found)
527 for _, f := range found {
528 sw.WriteString(f)
529 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900530 return true
531}