aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--func.go102
-rw-r--r--pathutil.go65
2 files changed, 152 insertions, 15 deletions
diff --git a/func.go b/func.go
index 60ffe77..93f9f31 100644
--- a/func.go
+++ b/func.go
@@ -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
}