Skip to content

Commit

Permalink
[#32] Allow raw pattern to be passed to fs/match (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude authored Oct 20, 2021
1 parent 80794be commit d3dfbd6
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 21 deletions.
63 changes: 44 additions & 19 deletions src/babashka/fs.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
(:require [clojure.java.io :as io]
[clojure.string :as str]
[clojure.walk :as walk])
(:import [java.io File FileInputStream FileOutputStream]
(:import [java.io File]
[java.nio.file CopyOption
#?@(:bb [] :clj [DirectoryStream]) #?@(:bb [] :clj [DirectoryStream$Filter])
Files
Expand All @@ -13,7 +13,7 @@
LinkOption Path
FileVisitor]
[java.nio.file.attribute FileAttribute FileTime PosixFilePermissions]
[java.util.zip ZipEntry ZipOutputStream ZipInputStream]))
[java.util.zip ZipInputStream]))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -234,38 +234,40 @@
(str/lower-case)
(str/includes? "win")))

(defn glob
"Given a file and glob pattern, returns matches as vector of
files. Patterns containing ** or / will cause a recursive walk over
path. Glob interpretation is done using the rules described in
(defn match
"Given a file and match pattern, returns matches as vector of
files. Pattern interpretation is done using the rules described in
https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String).
Options:
- :hidden: match hidden files. Note: on Windows files starting with
a dot are not hidden, unless their hidden attribute is set.
- :follow-links: follow symlinks."
([root pattern] (glob root pattern nil))
([root pattern {:keys [hidden follow-links max-depth]}]
- :follow-links: follow symlinks
- :recursive: match recursively.
- :max-depth: max depth to descend into directory structure.
Examples:
(fs/match \".\" \"regex:.*\\.clj\" {:recursive true})"
([root pattern] (match root pattern nil))
([root pattern {:keys [hidden follow-links max-depth recursive]}]
(let [base-path (-> root absolutize normalize)
base-path (if windows?
(str/replace base-path file-separator (str "\\" file-separator))
base-path)
skip-hidden? (not hidden)
results (atom (transient []))
past-root? (volatile! nil)
[base-path pattern recursive]
(let [recursive (or (str/includes? pattern "**")
(str/includes? pattern file-separator))
pattern (str base-path
;; we need to escape the file separator on Windows
(when windows? "\\")
file-separator
pattern)]
[base-path pattern recursive])
[prefix pattern] (str/split pattern #":")
pattern (str base-path
;; we need to escape the file separator on Windows
(when windows? "\\")
file-separator
pattern)
pattern (str prefix ":" pattern)
matcher (.getPathMatcher
(FileSystems/getDefault)
(str "glob:" pattern))
pattern)
match (fn [^Path path]
(if (.matches matcher path)
(swap! results conj! path)
Expand Down Expand Up @@ -296,6 +298,29 @@
results)
results)))))

(defn glob
"Given a file and glob pattern, returns matches as vector of
files. Patterns containing ** or / will cause a recursive walk over
path, unless overriden with :recursive. Glob interpretation is done
using the rules described in
https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String).
Options:
- :hidden: match hidden files. Note: on Windows files starting with
a dot are not hidden, unless their hidden attribute is set.
- :follow-links: follow symlinks.
- :recursive: force recursive search.
Examples:
(fs/glob \".\" \"**.clj\")"
([root pattern] (glob root pattern nil))
([root pattern opts]
(let [recursive (:recursive opts
(or (str/includes? pattern "**")
(str/includes? pattern file-separator)))]
(match root (str "glob:" pattern) (assoc opts :recursive recursive)))))

(defn- ->copy-opts ^"[Ljava.nio.file.CopyOption;"
[replace-existing copy-attributes atomic-move nofollow-links]
(into-array CopyOption
Expand Down
36 changes: 34 additions & 2 deletions test/babashka/fs_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,38 @@
Exception #":continue, :skip-subtree, :skip-siblings, :terminate"
(fs/walk-file-tree "." {:pre-visit-dir (fn [_ _])}))))

(deftest match-test
(is (= '("README.md") (map str (fs/match "." "regex:README.md"))))
(is (set/subset? #{"project.clj"
"test/babashka/fs_test.clj"
"src/babashka/fs.cljc"}
(set (map normalize
(fs/match "." "regex:.*\\.cljc?" {:recursive true})))))
(testing "match also matches directories and doesn't return the root directory"
(is (set/subset? #{"test-resources/foo/1" "test-resources/foo/foo"}
(set (map normalize
(fs/match "test-resources/foo" "regex:.*" {:recursive true})))))
(is (set/subset? #{"test-resources/foo/1" "test-resources/foo/foo"}
(set (map normalize
(fs/match "test-resources" "regex:foo.*" {:recursive true}))))))
(when-not windows?
(testing "symlink as root path"
(let [tmp-dir1 (temp-dir)
_ (spit (fs/file tmp-dir1 "dude.txt") "contents")
tmp-dir2 (temp-dir)
sym-link (fs/create-sym-link (fs/file tmp-dir2 "sym-link") tmp-dir1)]
(is (empty? (fs/match sym-link "regex:.*")))
(is (= 1 (count (fs/match sym-link "regex:.*" {:follow-links true}))))
(is (= 1 (count (fs/match (fs/real-path sym-link) "regex:.*")))))))
(testing "match with specific depth"
(let [tmp-dir1 (temp-dir)
nested-dir (fs/file tmp-dir1 "foo" "bar" "baz")
_ (fs/create-dirs nested-dir)
_ (spit (fs/file nested-dir "dude.txt") "contents")]
(is (= 1 (count (if windows?
(fs/match tmp-dir1 "regex:foo\\\\bar\\\\baz\\\\.*" {:recursive true})
(fs/match tmp-dir1 "regex:foo/bar/baz/.*" {:recursive true}))))))))

(deftest glob-test
(is (= '("README.md") (map str
(fs/glob "." "README.md"))))
Expand Down Expand Up @@ -145,8 +177,8 @@
(let [tmp-dir (temp-dir)]
(fs/delete tmp-dir)
(fs/copy-tree "." tmp-dir)
(let [cur-dir-count (count (fs/glob "." "**" #{:hidden}))
tmp-dir-count (count (fs/glob tmp-dir "**" #{:hidden}))]
(let [cur-dir-count (count (fs/glob "." "**" {:hidden true}))
tmp-dir-count (count (fs/glob tmp-dir "**" {:hidden true}))]
(is (pos? cur-dir-count))
(is (= cur-dir-count tmp-dir-count)))))

Expand Down

0 comments on commit d3dfbd6

Please sign in to comment.