add -use_find_cache
for $(shell if [ -d $1 ] ; then cd $1 ; find ./ -not -name '.*' -and -type f -and -not -type l ; fi),
it will look up find cache instead of invoking shell command.
% time ./repo/android.sh kati -c >/dev/null
find: `dummy': No such file or directory
find: `dummy': No such file or directory
fatal: Not a git repository: 'packages/apps/Camera2/.git'
./repo/android.sh kati -c > /dev/null 34.08s user 41.16s system 131% cpu 57.423 total
% time ./repo/android.sh kati -c -use_find_cache >/dev/null
find: `dummy': No such file or directory
find: `dummy': No such file or directory
fatal: Not a git repository: 'packages/apps/Camera2/.git'
./repo/android.sh kati -c -use_find_cache > /dev/null 35.82s user 33.25s system 142% cpu 48.495 total
diff --git a/pathutil.go b/pathutil.go
index ec683e1..a60668e 100644
--- a/pathutil.go
+++ b/pathutil.go
@@ -1,9 +1,13 @@
package main
import (
+ "os"
"os/exec"
"path/filepath"
+ "sort"
"strings"
+ "sync"
+ "time"
)
var wildcardCache = make(map[string][]string)
@@ -54,3 +58,96 @@
wildcardCache[pat] = files
}
}
+
+type fileInfo struct {
+ path string
+ mode os.FileMode
+}
+
+type androidFindCacheT struct {
+ once sync.Once
+ mu sync.Mutex
+ ok bool
+ files []fileInfo
+ scanTime time.Duration
+}
+
+var (
+ androidFindCache androidFindCacheT
+)
+
+func (c *androidFindCacheT) ready() bool {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.ok
+}
+
+func (c *androidFindCacheT) init() {
+ c.once.Do(func() {
+ c.mu.Lock()
+ go c.start()
+ })
+}
+
+func (c *androidFindCacheT) start() {
+ defer c.mu.Unlock()
+ t := time.Now()
+ defer func() {
+ c.scanTime = time.Since(t)
+ Logf("android find cache scan: %v", c.scanTime)
+ }()
+
+ err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ c.files = append(c.files, fileInfo{
+ path: strings.TrimPrefix(path, "./"),
+ mode: info.Mode(),
+ })
+ return nil
+ })
+ if err != nil {
+ Logf("error in adnroid find cache: %v", err)
+ c.ok = false
+ return
+ }
+ sort.Sort(fileInfoByName(c.files))
+ for i, fi := range c.files {
+ Logf("android find cache: %d: %s %v", i, fi.path, fi.mode)
+ }
+ c.ok = true
+}
+
+type fileInfoByName []fileInfo
+
+func (f fileInfoByName) Len() int { return len(f) }
+func (f fileInfoByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f fileInfoByName) Less(i, j int) bool {
+ return f[i].path < f[j].path
+}
+
+// if [ -d $1 ] ; then cd $1 ; find ./ -not -name '.*' -and -type f -and -not -type l ; fi
+func (c *androidFindCacheT) findInDir(sw *ssvWriter, dir string) {
+ dir = strings.TrimPrefix(dir, "./")
+ i := sort.Search(len(c.files), func(i int) bool {
+ return c.files[i].path >= dir
+ })
+ Logf("android find cache in dir: %s i=%d/%d", dir, i, len(c.files))
+ for ; i < len(c.files); i++ {
+ if c.files[i].path != dir && !strings.HasPrefix(c.files[i].path, dir+"/") {
+ Logf("android find cache in dir: %s different prefix: %s", dir, c.files[i].path)
+ break
+ }
+ // -not -name '.*'
+ if strings.HasPrefix(filepath.Base(c.files[i].path), ".") {
+ continue
+ }
+ // -type f and -not -type l
+ // regular type and not symlink
+ if !c.files[i].mode.IsRegular() {
+ continue
+ }
+ name := strings.TrimPrefix(c.files[i].path, dir+"/")
+ name = "./" + name
+ sw.WriteString(name)
+ Logf("android find cache in dir: %s=> %s", dir, name)
+ }
+}