commit 9d6ed7453df231d13b8706e06e76cd743ade6cbc Author: Niten Date: Sat Jul 9 10:51:47 2022 -0700 Initial checkin diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..35337f2 --- /dev/null +++ b/deps.edn @@ -0,0 +1,27 @@ +{ + :paths ["src"] + + :deps { + org.clojure/clojure { :mvn/version "1.11.1" } + org.clojure/core.async { :mvn/version "1.5.648" } + } + :aliases { + :test { + :extra-paths ["test"] + :extra-deps { + io.github.cognitect-labs/test-runner + { + :git/url "https://github.com/cognitect-labs/test-runner.git" + :sha "dfb30dd6605cb6c0efc275e1df1736f6e90d4d73" + } + } + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test + } + + :lint { + :replace-deps { clj-kondo/clj-kondo {:mvn/version "2022.04.25"} } + :main-opts ["-m" "clj-kondo.main" "--lint" "src"] + } + } + } diff --git a/src/firmament/connection.clj b/src/firmament/connection.clj new file mode 100644 index 0000000..8cc7e18 --- /dev/null +++ b/src/firmament/connection.clj @@ -0,0 +1,24 @@ +(ns firmament.connection + (:require [clojure.edn :as edn]) + (:import java.security.MessageDigest)) + +(defprotocol IFirmConnection + (read! [self id]) + (write! [self data])) + +(defn- sha256 [string] + (let [digest (.digest (MessageDigest/getInstance "SHA-256") + (.getBytes string "UTF-8"))] + (apply str (map (partial format "%02x") digest)))) + +(defn firmament-cache [] + (let [store (atom {})] + (reify IFirmConnection + (read! [_ id] + (some-> (get @store id) + (edn/read-string))) + (write! [_ data] + (let [data-str (-> data prn-str) + id (sha256 data-str)] + (swap! store assoc id data-str) + id))))) diff --git a/src/firmament/core.clj b/src/firmament/core.clj new file mode 100644 index 0000000..9352746 --- /dev/null +++ b/src/firmament/core.clj @@ -0,0 +1,26 @@ +(ns firmament.core + (:require [clojure.string :as str])) + +;; Namespaces and code files + +;; Dependencies specify namespaces, and the same rules as clojure apply + + +(defprotocol IFirmFilesystem + (read [self filename]) + (write [self filename content]) + (entries [self dirname])) + +(defn make-filesystem + ([conn] (make-filesystem [conn nil])) + ([conn original-root] + (let [root (atom original-root)] + (reify IFirmFilesystem + (read [_ path] + (read-file conn @root path)) + (write [_ path content] + (swap! root + (fn [old-root] + (write-path conn old-root path content)))) + (entries [_ dirname] + (list-entries conn @root dirname)))))) diff --git a/src/firmament/directory.clj b/src/firmament/directory.clj new file mode 100644 index 0000000..75d9d55 --- /dev/null +++ b/src/firmament/directory.clj @@ -0,0 +1,36 @@ +(ns firmament.directory + (:require [firmament.directory :as dir] + [firmament.type :as t] + [clojure.spec.alpha :as s])) + +(s/def ::entries (s/map-of keyword? ::t/firmament-id)) + +(defn create [& entries] + {::t/type ::t/directory + ::entries (apply hash-map entries)}) + +(defn entry-id [dir entry] + (get-in dir [::entries entry])) + +#_(defn- load-entry! [conn dir entry] + (conn/read! conn (get-entry-id dir entry))) + +#_(defn- read-or-create! [conn id] + (if-let [dir (conn/read! conn id)] + dir + (create))) + +#_(defn load! [conn dir entry] + (dir/read-or-create! conn (get-entry-id dir entry))) + +#_(defn add-entry! [conn dir entry data] + (assoc-in dir [::entries entry] (conn/write conn data))) + +(defn entries [dir] + (::entries dir)) + +(defn add-entry [dir entry id] + (assoc-in dir [::entries entry] id)) + +(defn directory? [o] + (and (map? o) (= ::t/directory (::t/type o)))) diff --git a/src/firmament/filesystem.clj b/src/firmament/filesystem.clj new file mode 100644 index 0000000..f5cd327 --- /dev/null +++ b/src/firmament/filesystem.clj @@ -0,0 +1,21 @@ +(ns firmament.filesystem + (:require [firmament.path :as path])) + +(defprotocol IFirmFilesystem + (read! [self filename]) + (write! [self filename content]) + (entries! [self dirname])) + +(defn make-filesystem + ([conn] (make-filesystem conn nil)) + ([conn original-root] + (let [root (atom original-root)] + (reify IFirmFilesystem + (read! [_ path] + (path/read-file! conn @root path)) + (write! [_ path content] + (swap! root + (fn [old-root] + (path/write! conn old-root path content)))) + (entries! [_ dirname] + (path/list-entries! conn @root dirname)))))) diff --git a/src/firmament/object.clj b/src/firmament/object.clj new file mode 100644 index 0000000..c53ea0c --- /dev/null +++ b/src/firmament/object.clj @@ -0,0 +1,8 @@ +(ns firmament.object + (:require [firmament.type :as t])) + +(defn create [data] + {::t/type ::t/object ::t/data data}) + +(defn data [obj] + (::t/data obj)) diff --git a/src/firmament/path.clj b/src/firmament/path.clj new file mode 100644 index 0000000..3bfcf8c --- /dev/null +++ b/src/firmament/path.clj @@ -0,0 +1,49 @@ +(ns firmament.path + (:require [clojure.string :as str] + [firmament.directory :as dir] + [firmament.object :as object] + [firmament.connection :as conn])) + +(defn- path-elements [path] + (str/split path #"/")) + +(defn- read! [conn root path] + (loop [curr (conn/read! conn root) + remaining (path-elements path)] + (when (nil? curr) + (throw (ex-info (str "path does not exist: " path) + {:root root}))) + (if (not (seq remaining)) + curr + (recur (conn/read! conn (dir/entry-id curr (first remaining))) + (rest remaining))))) + +(defn read-file! [conn root path] + (some-> (read! conn root path) (object/data))) + +(defn list-entries! [conn root path] + (some-> (read! conn root path) (dir/entries) (keys))) + +(defn save-entry! [conn dir entry data] + (dir/add-entry dir entry (conn/write! conn data))) + +(defn load-dir-entry! [conn base entry] + (if-let [dir (conn/read! conn (dir/entry-id base entry))] + dir + (dir/create))) + +(defn- write-internal [conn curr [el & els] obj] + (if (seq els) + (save-entry! conn curr el + (write-internal conn + (load-dir-entry! conn curr el) + els + obj)) + (save-entry! conn curr el obj))) + +(defn write! [conn root path data] + (conn/write! conn + (write-internal conn + (conn/read! conn root) + (path-elements path) + (object/create data)))) diff --git a/src/firmament/type.clj b/src/firmament/type.clj new file mode 100644 index 0000000..741cb1d --- /dev/null +++ b/src/firmament/type.clj @@ -0,0 +1,12 @@ +(ns firmament.type + (:require [clojure.spec.alpha :as s])) + +(def firmament-id? string?) + +(s/def ::firmament-id firmament-id?) + +(def firmament-data? string?) + +(s/def ::type #{::directory ::object}) + +(s/def ::data firmament-data?)