]> gitweb.factorcode.org Git - factor.git/commitdiff
globs: implement glob-directory.
authorJohn Benediktsson <mrjbq7@gmail.com>
Mon, 28 Mar 2016 01:52:20 +0000 (18:52 -0700)
committerJohn Benediktsson <mrjbq7@gmail.com>
Mon, 28 Mar 2016 01:52:20 +0000 (18:52 -0700)
It looks too complicated, and maybe it is.  Some tests pass.

basis/globs/globs-tests.factor
basis/globs/globs.factor

index f9b476bca415bc6a2b0cd225e51dc4560a429314..c048af9eb615415a6d805edb7f9de494ed9b64ca 100755 (executable)
@@ -1,4 +1,5 @@
-USING: globs io.pathnames literals sequences tools.test ;
+USING: globs io.directories io.files.temp io.files.unique
+io.pathnames literals sequences tools.test ;
 IN: globs.tests
 
 { f } [ "abd" "fdf" glob-matches? ] unit-test
@@ -30,6 +31,57 @@ IN: globs.tests
 { t } [ "fo\\*" glob-pattern? ] unit-test
 { t } [ "fo{o,bro}" glob-pattern? ] unit-test
 
+{
+    { "a" }
+    { "a" "a/b" "a/b/c" "a/b/c/d" "a/b/h" "a/e" "a/e/g" }
+    {
+        "a" "a/b" "a/b/c" "a/b/c/d" "a/b/c/d/e" "a/b/c/f"
+        "a/b/g" "a/b/h" "a/b/h/e" "a/e" "a/e/f" "a/e/g"
+        "a/e/g/e"
+    }
+    {
+        "a" "a/b" "a/b/c" "a/b/c/d" "a/b/c/d/e" "a/b/c/f"
+        "a/b/g" "a/b/h" "a/b/h/e" "a/e" "a/e/f" "a/e/g"
+        "a/e/g/e"
+    }
+    { "a/b" }
+    { "a/b/c/d/e" "a/b/h/e" "a/e" "a/e/g/e" }
+    ! { "a/b/c/d/e" "a/b/h/e" "a/e" "a/e/g/e" }
+    ! { "a/b/c/d/e" "a/b/h/e" "a/e" "a/e/g/e" }
+    { "a/e/f" "a/e/g" }
+    { "a/b" "a/e" }
+} [
+
+    [
+        [
+            "a" make-directory
+            "a/b" make-directory
+            "a/b/c" make-directory
+            "a/b/c/d" make-directory
+            "a/b/c/d/e" touch-file
+            "a/b/c/f" touch-file
+            "a/b/g" touch-file
+            "a/b/h" make-directory
+            "a/b/h/e" touch-file
+            "a/e" make-directory
+            "a/e/f" touch-file
+            "a/e/g" make-directory
+            "a/e/g/e" touch-file
+
+            "**" glob-directory
+            "**/" glob-directory
+            "**/*" glob-directory
+            "**/**" glob-directory
+            "**/b" glob-directory
+            "**/e" glob-directory
+            ! "**//e" glob-directory
+            ! "**/**/e" glob-directory
+            "**/e/**" glob-directory
+            "a/**" glob-directory
+        ] cleanup-unique-directory
+    ] with-temp-directory
+] unit-test
+
 ${ { "foo" "bar" } path-separator join }
 [ { "foo" "bar" "ba?" } path-separator join glob-parent-directory ] unit-test
 
index 9cd6a73891b4e95093dd6b54a80eb944ecb5f5a5..a22330ffa48762472a881c7ce968f83188c7e040 100644 (file)
@@ -1,7 +1,9 @@
 ! Copyright (C) 2007, 2009 Slava Pestov, Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: sequences io.pathnames kernel regexp.combinators
-strings splitting system unicode.case peg.ebnf regexp arrays ;
+USING: accessors arrays combinators combinators.short-circuit
+io.directories io.files io.files.info io.pathnames kernel locals
+make peg.ebnf regexp regexp.combinators sequences splitting
+strings system unicode.case ;
 IN: globs
 
 : not-path-separator ( -- sep )
@@ -47,6 +49,103 @@ Main = Concatenation End
 : glob-pattern? ( string -- ? )
     [ "\\*?[{" member? ] any? ;
 
+<PRIVATE
+
+DEFER: glob-directory%
+
+: ?glob-directory% ( root remaining entry -- )
+    directory? [
+        glob-directory%
+    ] [
+        empty? [ , ] [ drop ] if
+    ] if ;
+
+:: glob-wildcard% ( root globs -- )
+    globs ?second :> next-glob
+    next-glob dup pair? [ second ] [ drop f ] if :> next-glob-regexp
+
+    root directory-entries [| entry |
+        root entry name>> append-path
+        {
+            { [ next-glob not ] [ dup , ] }
+            { [ next-glob empty? ] [ entry directory? [ dup , ] when ] }
+            [
+                next-glob-regexp [
+                    entry name>> >case-fold next-glob-regexp matches?
+                ] [
+                    {
+                        [ next-glob "**" = ]
+                        [ entry name>> next-glob = ]
+                    } 0||
+                ] if [
+                    globs 2 tail [
+                         dup ,
+                    ] [
+                        entry directory? [
+                            dupd glob-directory%
+                        ] [
+                            drop
+                        ] if
+                    ] if-empty
+                ] when
+            ]
+        } cond
+
+        { [ entry directory? ] [ next-glob ] } 0&& [
+            globs glob-directory%
+        ] [
+            drop
+        ] if
+    ] each ;
+
+:: glob-pattern% ( root globs -- )
+    globs unclip second :> ( remaining glob )
+
+    root directory-entries [| entry |
+        entry name>> >case-fold glob matches? [
+            root entry name>> append-path
+            remaining entry ?glob-directory%
+        ] when
+    ] each ;
+
+:: glob-literal% ( root globs -- )
+    globs unclip :> ( remaining glob )
+
+    root glob append-path dup exists? [
+        remaining over file-info ?glob-directory%
+    ] [
+        drop
+    ] if ;
+
+: glob-directory% ( root globs -- )
+    dup ?first {
+        { f [ 2drop ] }
+        { "**" [ glob-wildcard% ] }
+        [ pair? [ glob-pattern% ] [ glob-literal% ] if ]
+    } case ;
+
+: split-glob ( glob -- path globs )
+    { } [
+        over glob-pattern?
+    ] [
+        [
+            path-separator first over last-index
+            [ cut rest ] [ "" swap ] if*
+        ] dip swap prefix
+    ] while ;
+
+: glob-path ( glob -- path globs )
+    split-glob [
+        dup { [ "**" = not ] [ glob-pattern? ] } 1&& [
+            dup >case-fold <glob> 2array
+        ] when
+    ] map ;
+
+PRIVATE>
+
+: glob-directory ( glob -- files )
+    glob-path [ glob-directory% ] { } make ;
+
 : glob-parent-directory ( glob -- parent-directory )
     path-separator split harvest dup [ glob-pattern? ] find drop head
     path-separator join ;