diff options
-rw-r--r-- | func.go | 102 | ||||
-rw-r--r-- | pathutil.go | 65 |
2 files changed, 152 insertions, 15 deletions
@@ -757,6 +757,14 @@ func (f *funcShell) Compact() Value { dir: dir, } } + if chdir, roots, ok := matchAndroidFindJavaInDir(expr); ok { + androidFindCache.init() + return &funcShellAndroidFindJavaInDir{ + funcShell: f, + chdir: chdir, + roots: roots, + } + } return f } @@ -789,16 +797,6 @@ func matchAndroidFindFileInDir(expr Expr) (Value, bool) { return paramref(1), true } -// TODO(ukai): pattern: -// cd ${LOCAL_PATH} ; find -L $1 -name "*.java" -and -not -name ".*" -// -// cd ${TOP_DIR}${LOCAL_PATH}/${dir} && find . -type d -a -name ".svn" -prune \ -// -o -type f -a \! -name "*.java" -a \! -name "package.html" -a \! \ -// -name "overview.html" -a \! -name ".*.swp" -a \! -name ".DS_Store" \ -// -a \! -name "*~" -print ) -// -// echo $1 | tr 'a-zA-Z' 'n-za-mN-ZA-M' - type funcShellAndroidFindFileInDir struct { *funcShell dir Value @@ -824,6 +822,90 @@ func (f *funcShellAndroidFindFileInDir) Eval(w io.Writer, ev *Evaluator) { androidFindCache.findInDir(&sw, dir) } +// pattern: +// cd ${LOCAL_PATH} ; find -L $1 -name "*.java" -and -not -name ".*" +func matchAndroidFindJavaInDir(expr Expr) (Value, Value, bool) { + // literal: "cd " + // varref: xxx + // literal: " ; find -L " + // paramref: 1 + // literal: " -name "*.java" -and -not -name ".*" + if len(expr) != 5 { + return nil, nil, false + } + if expr[0] != literal("cd ") { + return nil, nil, false + } + if _, ok := expr[1].(varref); !ok { + return nil, nil, false + } + if expr[2] != literal(" ; find -L ") { + return nil, nil, false + } + if expr[3] != paramref(1) { + return nil, nil, false + } + if expr[4] != literal(` -name "*.java" -and -not -name ".*"`) { + return nil, nil, false + } + return expr[1], paramref(1), true +} + +type funcShellAndroidFindJavaInDir struct { + *funcShell + chdir Value + roots Value +} + +func (f *funcShellAndroidFindJavaInDir) Eval(w io.Writer, ev *Evaluator) { + abuf := newBuf() + fargs := ev.args(abuf, f.chdir, f.roots) + chdir := string(trimSpaceBytes(fargs[0])) + var roots []string + hasDotDot := false + ws := newWordScanner(fargs[1]) + for ws.Scan() { + root := string(ws.Bytes()) + if strings.Contains(root, "..") { + hasDotDot = true + } + roots = append(roots, string(ws.Bytes())) + } + freeBuf(abuf) + Logf("shellAndroidFindJavaInDir %s,%s => %s,%s", f.chdir.String(), f.roots.String(), chdir, roots) + if strings.Contains(chdir, "..") || hasDotDot { + Logf("shellAndroidFindJavaInDir contains ..: call original shell") + f.funcShell.Eval(w, ev) + return + } + if !androidFindCache.ready() { + Logf("shellAndroidFindJavaInDir androidFindCache is not ready: call original shell") + f.funcShell.Eval(w, ev) + return + } + buf := newBuf() + sw := ssvWriter{w: buf} + for _, root := range roots { + if !androidFindCache.findJavaInDir(&sw, chdir, root) { + freeBuf(buf) + Logf("shellAndroidFindJavaInDir androidFindCache couldn't handle: call original shell") + f.funcShell.Eval(w, ev) + return + } + } + w.Write(buf.Bytes()) + freeBuf(buf) +} + +// TODO(ukai): pattern: +// +// cd ${TOP_DIR}${LOCAL_PATH}/${dir} && find . -type d -a -name ".svn" -prune \ +// -o -type f -a \! -name "*.java" -a \! -name "package.html" -a \! \ +// -name "overview.html" -a \! -name ".*.swp" -a \! -name ".DS_Store" \ +// -a \! -name "*~" -print ) +// +// echo $1 | tr 'a-zA-Z' 'n-za-mN-ZA-M' + // https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function type funcCall struct{ fclosure } diff --git a/pathutil.go b/pathutil.go index a60668e..4a9113c 100644 --- a/pathutil.go +++ b/pathutil.go @@ -130,11 +130,16 @@ func (c *androidFindCacheT) findInDir(sw *ssvWriter, dir string) { 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)) + Logf("android find in dir cache: %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 + if c.files[i].path != dir { + if !strings.HasPrefix(c.files[i].path, dir) { + Logf("android find in dir cache: %s different prefix at %d: %s", dir, i, c.files[i].path) + break + } + if !strings.HasPrefix(c.files[i].path, dir+"/") { + continue + } } // -not -name '.*' if strings.HasPrefix(filepath.Base(c.files[i].path), ".") { @@ -148,6 +153,56 @@ func (c *androidFindCacheT) findInDir(sw *ssvWriter, dir string) { name := strings.TrimPrefix(c.files[i].path, dir+"/") name = "./" + name sw.WriteString(name) - Logf("android find cache in dir: %s=> %s", dir, name) + Logf("android find in dir cache: %s=> %s", dir, name) + } +} + +// cd ${LOCAL_PATH} ; find -L $1 -name "*.java" -and -not -name ".*" +// returns false if symlink is found. +func (c *androidFindCacheT) findJavaInDir(sw *ssvWriter, chdir string, root string) bool { + chdir = strings.TrimPrefix(chdir, "./") + dir := filepath.Join(chdir, root) + i := sort.Search(len(c.files), func(i int) bool { + return c.files[i].path >= dir + }) + Logf("android find java in dir cache: %s i=%d/%d", dir, i, len(c.files)) + start := i + end := len(c.files) + // check symlinks + for ; i < len(c.files); i++ { + if c.files[i].path != dir { + if !strings.HasPrefix(c.files[i].path, dir) { + Logf("android find in dir cache: %s different prefix at %d: %s", dir, i, c.files[i].path) + end = i + break + } + if !strings.HasPrefix(c.files[i].path, dir+"/") { + continue + } + } + if c.files[i].mode&os.ModeSymlink == os.ModeSymlink { + Logf("android find java in dir cache: detect symlink %s %v", c.files[i].path, c.files[i].mode) + return false + } + } + + // no symlinks + for i := start; i < end; i++ { + if c.files[i].path != dir && !strings.HasPrefix(c.files[i].path, dir+"/") { + continue + } + base := filepath.Base(c.files[i].path) + // -name "*.java" + if filepath.Ext(base) != ".java" { + continue + } + // -not -name ".*" + if strings.HasPrefix(base, ".") { + continue + } + name := strings.TrimPrefix(c.files[i].path, chdir+"/") + sw.WriteString(name) + Logf("android find java in dir cache: %s=> %s", dir, name) } + return true } |