sidenotes.fs

table of contents

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))))