This namespace contains all the functions we need to handle accessing the filesystem as well as resources inside the project itself.
(ns sidenotes.fs
  (:require
    [clojure.string :as string]
    [clojure.java.io :as io]))
			Check if the given path points to an existing file.
(defn file?
  [path]
  (let [file (java.io.File. path)]
    (and (.exists file) (.isFile file))))
			Performs roughly the same task as the UNIX ls.  That is, returns a seq of the filenames  at a given directory.  If a path to a file is supplied, then the seq contains only the  original path given.
(defn ls
  [path]
  (let [file (java.io.File. path)]
    (if (.isDirectory file)
      (seq (.list file))
      (when (.exists file)
        [path]))))
			Create a directory for the given path.
(defn mkdir [path] (.mkdirs (io/file path)))
Ensure that the directory specified by path exists.  If not then make it so.  Here is a snowman ☃
(defn ensure-directory!
  [path]
  (when-not (ls path)
    (mkdir path)))
			Many Marginalia fns use dir? to recursively search a filepath.
(defn dir? [path] (.isDirectory (java.io.File. path)))
Shorten full file path by removing current dir prefix.
(defn shorten
  [path]
  (let [pwd (.getAbsolutePath (java.io.File. ""))]
    (if (.startsWith path pwd) (.substring path (inc (count pwd))) path)))
			Returns a string containing the files extension.
(defn file-extension [filename] (second (re-find #"\\.([^.]+)\$" filename)))
Returns a string containing the files extension for a File instance.
(defn find-file-extension [^java.io.File file] (file-extension (.getName file)))
Predicate. Returns true for "normal" files with a file extension which passes the provided predicate.
(defn processable-file?
  [pred ^java.io.File file]
  (when (.isFile file)
    (-> file find-file-extension pred)))
			Returns a seq of processable file paths (strings) in alphabetical order by namespace.
(defn find-processable-file-paths
  [dir pred]
  (->> (io/file dir)
       (file-seq)
       (filter (partial processable-file? pred))
       (sort)
       (map #(.getCanonicalPath %))))
			(def ^:private file-extensions #{"clj" "cljs" "cljx" "cljc"})
			Given a collection of filepaths, returns a lazy sequence of filepaths to all .clj, .cljs, .cljx, and .cljc files on those paths: directory paths will be searched recursively for files.
(defn find-sources
  [sources]
  (if (nil? sources)
    (find-processable-file-paths "./src" file-extensions)
    (->> sources
         (mapcat #(if (dir? %)
                    (find-processable-file-paths % file-extensions)
                    [(.getCanonicalPath (io/file %))])))))
			Try to find the readme file.
(defn find-readme [] (first (filter #(.startsWith (string/lower-case %) "readme") (ls "."))))
Load the readme file if possible.
(defn load-readme
  []
  (let [readme (find-readme)]
    (if (nil? readme)
      {:has-readme false}
      {:has-readme true
       :file readme
       :type (string/lower-case (find-file-extension (io/file readme)))
       :content (slurp readme)})))
			Find the name of the project from current folder.
(defn project-folder [] (last (clojure.string/split (str (io/as-url (io/file ""))) #"/")))
Stolen from leiningen
(defn slurp-resource
  [resource-name]
  (try
    (-> (.getContextClassLoader (Thread/currentThread))
        (.getResourceAsStream resource-name)
        (java.io.InputStreamReader.)
        (slurp))
    (catch java.lang.NullPointerException npe
      (println (str "Could not locate resources at " resource-name))
      (println "    ... attempting to fix.")
      (let [resource-name resource-name]
        (try
          (-> (.getContextClassLoader (Thread/currentThread))
              (.getResourceAsStream resource-name)
              (java.io.InputStreamReader.)
              (slurp))
          (catch java.lang.NullPointerException npe
            (println (str "    STILL could not locate resources at " resource-name ". Giving up!"))))))))
			Load a resource and spit it to the output folder.
(defn spit-resource [resource from to] (ensure-directory! (str to "/" (string/join "/" (butlast (string/split resource #"/"))))) (dorun (println (str "\\t" resource " to " to))) (spit (str to "/" resource) (slurp-resource (str from "/" resource))))
Copy a file to the output folder.
(defn copy-file [file from to] (ensure-directory! (str to "/" (string/join "/" (butlast (string/split file #"/"))))) (dorun (println (str "\\t" file " to " to))) (io/copy (io/file (str from "/" file)) (io/file (str to "/" file))))