diff --git a/bb.edn b/bb.edn index 1c636c44..3bad1ec2 100644 --- a/bb.edn +++ b/bb.edn @@ -1,4 +1,5 @@ -{:deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.72"}} +;;The file is updated automatically +{:deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.74"}} :paths [] :tasks {:requires [[automaton-build-app.tasks.launcher.bb-entrypoint :as build-task-bb-entrypoint] [babashka.process :as babahska-process]] heph-task {:doc "Launch an Hephaistox task" @@ -6,4 +7,4 @@ lconnect {:doc "Repl in case automaton-core is failing. Using -f or --force cli arguments to force start if some part are failing" :task (try (-> (babahska-process/shell "clojure" "-M:common-test:env-development-repl:build" *command-line-args*) System/exit) - (catch Exception e (println "Repl failed also - error during repl startup" (ex-message e))))}}} + (catch Exception e (println "Repl failed also - error during repl startup" (ex-message e))))}}} \ No newline at end of file diff --git a/build_config.edn b/build_config.edn index b83b860c..350caed1 100644 --- a/build_config.edn +++ b/build_config.edn @@ -1,14 +1,9 @@ {:app-name "automaton-core" :task-shared {:gha {} - :mermaid-dir "docs/code/" :publication {:as-lib org.clojars.hephaistox/automaton-core - :branch "main" :deploy-to :clojars - :jar-path "target/prod/automaton-core.jar" :major-version "0.0.%d" - :pom-path "target/prod/class/META-INF/maven/org.clojars.hephaistox/automaton-core/pom.xml" :repo "git@github.com:hephaistox/automaton-core.git"} - :repl-aliases [:common-test :env-development-repl :build] - :storage-datomic {:datomic-ver "1.0.7021"}} + :repl-aliases [:common-test :env-development-repl :build]} :tasks {:clean {:dirs [".cpcache/" ".clj-kondo/.cache/" "tmp/" "target/" "node_modules/" ".shadow-cljs/builds/"]} :reports {:forbiddenwords-words #{"automaton-web" "landing" "tap>"}}}} diff --git a/deps.edn b/deps.edn index 141ccf91..d00d8beb 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,5 @@ -{:aliases {:bb-deps {:extra-deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.72"}}} - :build {:extra-deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.72"}}} +{:aliases {:bb-deps {:extra-deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.74"}}} + :build {:extra-deps {org.clojars.hephaistox/automaton-build-app {:mvn/version "0.0.74"}}} :cljs-deps {:extra-deps {binaryage/devtools {:mvn/version "1.0.7"} cider/cider-nrepl {:mvn/version "0.30.0"} thheller/shadow-cljs {:mvn/version "2.26.2"}} @@ -28,7 +28,7 @@ org.clojure/data.json {:mvn/version "2.5.0"} com.taoensso/tempura {:mvn/version "1.5.3"} danlentz/clj-uuid {:mvn/version "0.1.9"} - djblue/portal {:mvn/version "0.51.0"} ;; developer tooling + djblue/portal {:mvn/version "0.51.1"} ;; developer tooling http-kit/http-kit {:mvn/version "2.7.0"} io.sentry/sentry {:mvn/version "7.1.0"} io.sentry/sentry-clj {:mvn/version "6.33.209"} diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..039d8b56 --- /dev/null +++ b/pom.xml @@ -0,0 +1,151 @@ + + + 4.0.0 + jar + org.clojars.hephaistox + automaton-core + 0.0.55 + automaton-core + + + org.clojure + data.json + 2.5.0 + + + org.clojure + clojure + 1.11.1 + + + org.apache.logging.log4j + log4j-slf4j2-impl + 2.22.1 + + + org.clojure + tools.logging + 1.2.4 + + + org.clojure + tools.cli + 1.0.219 + + + danlentz + clj-uuid + 0.1.9 + + + com.clojure-goes-fast + clj-memory-meter + 0.3.0 + + + com.taoensso + encore + 3.62.1 + + + io.sentry + sentry + 7.1.0 + + + com.datomic + peer + 1.0.7075 + + + io.sentry + sentry-clj + 6.33.209 + + + org.postgresql + postgresql + 42.7.1 + + + com.taoensso + tempura + 1.5.3 + + + refactor-nrepl + refactor-nrepl + 3.6.0 + + + djblue + portal + 0.51.1 + + + org.apache.logging.log4j + log4j-core + 2.22.1 + + + zprint + zprint + 1.2.8 + + + metosin + malli + 0.13.0 + + + babashka + process + 0.5.21 + + + nrepl + nrepl + 1.1.0 + + + mount + mount + 0.1.17 + + + org.apache.logging.log4j + log4j-api + 2.22.1 + + + lambdaisland + uri + 1.16.134 + + + babashka + fs + 0.5.20 + + + http-kit + http-kit + 2.7.0 + + + + env/development/src/clj/ + + + + clojars + https://repo.clojars.org/ + + + + + Eclipse Public License 1.0 + https://opensource.org/license/epl-1-0/ + + + diff --git a/src/clj/automaton_core/log/be_log.clj b/src/clj/automaton_core/log/be_log.clj index 9155c46b..2c26e860 100644 --- a/src/clj/automaton_core/log/be_log.clj +++ b/src/clj/automaton_core/log/be_log.clj @@ -4,7 +4,8 @@ Current structure is generic for logging level, as they are the same right now in sense of this proxy. In future it may develop if needed to e.g. have the same number of macros as in `automaton-core.log`." (:require [automaton-core.log.be-registry :as log-be-registry] - [automaton-core.log.tracking.be-error-tracking :as exs])) + [automaton-core.log.tracking.be-error-tracking :as exs] + [automaton-core.log.terminal :as core-terminal])) (defn log-init! [{:keys [dsn env]}] @@ -17,7 +18,7 @@ (reduce (fn [acc logger-id] (if-let [logger-strategy (get-in log-be-registry/strategies-registry [logger-id :impl])] (conj acc logger-strategy) - (do (print "WARN: Logging strategy is nil for id: " logger-id) acc))) + (do (core-terminal/log "WARN: Logging strategy is nil for id: " logger-id) acc))) [] logger-ids)) diff --git a/src/clj/automaton_core/storage/component.clj b/src/clj/automaton_core/storage/component.clj index fd799cfc..a29725a4 100644 --- a/src/clj/automaton_core/storage/component.clj +++ b/src/clj/automaton_core/storage/component.clj @@ -12,7 +12,8 @@ (try (core-log/info "Start storage component") (let [dc (datomic/make-datomic-client datomic-schema/all-schema) db-uri (conf/read-param [:storage :datomic :url]) - _db-uri-valid? (when-not db-uri (throw (ex-info "Database uri was not found." {}))) + _db-uri-valid? (when-not db-uri + (throw (ex-info "Database uri was not found. Are you sure that env variable STORAGE_DATOMIC_URL is set?" {}))) conn (storage/connection dc db-uri) access (datomic/make-datomic-access)] (core-log/trace "Storage component is started") diff --git a/src/cljc/automaton_core/configuration.cljc b/src/cljc/automaton_core/configuration.cljc index b88bcebe..ede8cd09 100644 --- a/src/cljc/automaton_core/configuration.cljc +++ b/src/cljc/automaton_core/configuration.cljc @@ -11,7 +11,8 @@ gathering all classpath, so all `config.edn` versions. The solution was to be based on environment parameter. So each alias can tell which version it uses, especially monorepo could be different." (:require [automaton-core.configuration.protocol :as core-conf-prot] - [automaton-core.configuration.simple-files :as simple-files] + [automaton-core.configuration.files :as core-conf-files] + [automaton-core.configuration.environment :as core-conf-env] [mount.core :refer [defstate in-cljc-mode]])) ;; Force the use of `cljc mode` in mount library, so call to `@` will work @@ -20,9 +21,10 @@ (defn start-conf [] (try (println "Starting configuration component") - (let [conf (simple-files/->SimpleConf)] + (let [conf (core-conf-files/->SimpleConf) + env-conf (core-conf-env/->EnvConf)] (println "Configuration component is started") - conf) + [conf env-conf]) (catch #?(:clj Throwable :cljs :default) e @@ -35,11 +37,11 @@ (defn read-param "Returns value under `key-path` vector." ([key-path default-value] - (let [value (core-conf-prot/read-conf-param @conf-state key-path)] - (if (nil? value) - (do (println "Value for " key-path " is not set, use default value" default-value) default-value) - (do (println "Read key-path " key-path " = " value) value)))) + (let [value (or (core-conf-prot/read-conf-param (first @conf-state) key-path) + (core-conf-prot/read-conf-param (second @conf-state) key-path))] + (when (nil? value) + (println "Value for " key-path " is not set, use default value") + default-value))) ([key-path] (read-param key-path nil))) -#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} -(defn all-config "Returns whole configuration map, with all the keys and values." [] (core-conf-prot/config @conf-state)) + diff --git a/src/cljc/automaton_core/configuration/environment.cljc b/src/cljc/automaton_core/configuration/environment.cljc new file mode 100644 index 00000000..ed21c505 --- /dev/null +++ b/src/cljc/automaton_core/configuration/environment.cljc @@ -0,0 +1,54 @@ +(ns automaton-core.configuration.environment + (:require #?@(:clj [[clojure.edn :as edn]] + :cljs [[cljs.reader :as edn] [goog.object :as obj]]) + [automaton-core.configuration.protocol :as core-conf-prot] + [automaton-core.utils.keyword :as utils-keyword] + [clojure.string :as str])) + +#?(:cljs (def ^:private nodejs? (exists? js/require))) + +#?(:cljs (def ^:private process (when nodejs? (js/require "process")))) + +(defn env-key-path + "Turns key-path ([:a :b :c] -> 'a-b-c') into environment type key." + [key-path] + (let [path-str (str/join "-" (map name key-path))] (when-not (str/blank? path-str) (utils-keyword/keywordize path-str)))) + +(defn parse-number + [^String v] + (try #?(:clj (Long/parseLong v) + :cljs (parse-long v)) + #?(:clj (catch NumberFormatException _ (BigInteger. v))) + (catch #?(:clj Exception + :cljs js/Error) + _ + v))) + +#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]} +(defn parse-system-env + "Turns string type into number. In case of failure in parsing it's returned in a format as it was (a string)." + [v] + (cond (re-matches #"[0-9]+" v) (parse-number v) + (re-matches #"^(true|false)$" v) #?(:clj (Boolean/parseBoolean v) + :cljs (parse-boolean v)) + (re-matches #"\w+" v) v + :else (try (let [parsed (edn/read-string v)] (if (symbol? parsed) v parsed)) + (catch #?(:clj Exception + :cljs js/Error) + _ + v)))) + +(defn read-all + "Reads all system env properties and converts to appropriate type." + [] + (->> #?(:clj (System/getenv) + :cljs (if process (let [env (.-env process)] (zipmap (obj/getKeys env) (obj/getValues env))) {})) + (map (fn [[k v]] [(utils-keyword/keywordize k) v])) + (into {}))) + +(def ^{:doc "A map of configuration variables."} conf (memoize read-all)) + +(defrecord EnvConf [] + core-conf-prot/Conf + (read-conf-param [_this key-path] (get (conf) (env-key-path key-path))) + (config [_this] (conf))) diff --git a/src/cljc/automaton_core/configuration/simple_files.cljc b/src/cljc/automaton_core/configuration/files.cljc similarity index 53% rename from src/cljc/automaton_core/configuration/simple_files.cljc rename to src/cljc/automaton_core/configuration/files.cljc index 95cc375a..0ca7c219 100644 --- a/src/cljc/automaton_core/configuration/simple_files.cljc +++ b/src/cljc/automaton_core/configuration/files.cljc @@ -1,50 +1,16 @@ -(ns automaton-core.configuration.simple-files +(ns automaton-core.configuration.files "Namespace for simple configuration based on local file. Just like in core configuration, we are not using log nor outside dependencies to comply with the configuration requirements." (:require #?@(:clj [[clojure.edn :as edn] [clojure.java.io :as io] [automaton-core.adapters.java-properties :as java-properties]] - :cljs [[cljs.reader :as edn] [goog.object :as obj]]) + :cljs [[cljs.reader :as edn]]) [automaton-core.configuration.protocol :as core-conf-prot] [automaton-core.utils.keyword :as utils-keyword] - [automaton-core.utils.map :as utils-map] - [clojure.string :as str])) + [automaton-core.utils.map :as utils-map])) #?(:cljs (def ^:private nodejs? (exists? js/require))) #?(:cljs (def ^:private fs (when nodejs? (js/require "fs")))) -#?(:cljs (def ^:private process (when nodejs? (js/require "process")))) - -(defn parse-number - [^String v] - (try #?(:clj (Long/parseLong v) - :cljs (parse-long v)) - #?(:clj (catch NumberFormatException _ (BigInteger. v))) - (catch #?(:clj Exception - :cljs js/Error) - _ - v))) - -(defn parse-system-env - "Turns string type into number. In case of failure in parsing it's returned in a format sa it was (a string)." - [v] - (cond (re-matches #"[0-9]+" v) (parse-number v) - (re-matches #"^(true|false)$" v) #?(:clj (Boolean/parseBoolean v) - :cljs (parse-boolean v)) - (re-matches #"\w+" v) v - :else (try (let [parsed (edn/read-string v)] (if (symbol? parsed) v parsed)) - (catch #?(:clj Exception - :cljs js/Error) - _ - v)))) - -(defn read-system-env - "Reads system env properties and converts to appropriate type." - [] - (->> #?(:clj (System/getenv) - :cljs (zipmap (obj/getKeys (.-env process)) (obj/getValues (.-env process)))) - (map (fn [[k v]] [(utils-keyword/keywordize k) (parse-system-env v)])) - (into {}))) - (defn slurp-file [f] (try #?(:clj (when-let [file (or (io/resource f) (io/file f))] (slurp file)) @@ -83,20 +49,13 @@ property->config-files (mapv read-config-file) (filterv some?) - (apply merge-configs (read-system-env))) - :cljs (if nodejs? - (->> (read-config-file config-file) - (merge-configs (read-system-env))) - {}))) + (apply merge-configs)) + :cljs (if nodejs? (read-config-file config-file) {}))) (def ^{:doc "A map of configuration variables."} conf (memoize read-config)) -(defn env-key-path - "Turns key-path into environment type key." - [key-path] - (let [path-str (str/join "-" (map name key-path))] (when-not (str/blank? path-str) (keyword path-str)))) (defrecord SimpleConf [] core-conf-prot/Conf - (read-conf-param [_this key-path] (or (get-in (conf) key-path) (get (conf) (env-key-path key-path)))) + (read-conf-param [_this key-path] (get-in (conf) key-path)) (config [_this] (conf))) diff --git a/src/cljc/automaton_core/log/terminal.cljc b/src/cljc/automaton_core/log/terminal.cljc new file mode 100644 index 00000000..838f652b --- /dev/null +++ b/src/cljc/automaton_core/log/terminal.cljc @@ -0,0 +1,3 @@ +(ns automaton-core.log.terminal) + +(defn log [& msg] (apply println msg)) diff --git a/src/cljc/automaton_core/utils/keyword.cljc b/src/cljc/automaton_core/utils/keyword.cljc index b3527236..b157702a 100644 --- a/src/cljc/automaton_core/utils/keyword.cljc +++ b/src/cljc/automaton_core/utils/keyword.cljc @@ -5,18 +5,17 @@ (defn keywordize "Change string to appropriate clojure keyword" [s] - (-> (str/lower-case s) + (-> (name s) + str/lower-case (str/replace "_" "-") (str/replace "." "-") (keyword))) -(defn sanitize-key "Changes keyword to appropriate clojure keyword." [k] (let [s (keywordize (name k))] s)) - (defn sanitize-map-keys "Changes all keywords in a map to appropriate clojure keys." [map] (reduce-kv (fn [acc key value] - (let [new-key (if (keyword? key) (sanitize-key key) key) + (let [new-key (if (keyword? key) (keywordize key) key) new-val (if (map? value) (sanitize-map-keys value) value)] (assoc acc new-key new-val))) {} diff --git a/src/cljc/automaton_core/utils/map.cljc b/src/cljc/automaton_core/utils/map.cljc index 50da3bea..914ac4c9 100644 --- a/src/cljc/automaton_core/utils/map.cljc +++ b/src/cljc/automaton_core/utils/map.cljc @@ -107,3 +107,9 @@ (cond (map? v) [k (modify-type-fn v)] (and (some? v) (some? k)) [k v])))] (walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) + +(defn replace-keys + "Replace keys in `m2` with keys from `m1`. Similiar to merge but non-existen keys in first map won't be added. e.g. (replace-keys {:a 3 :b 2} {:a 1}) -> {:a 3}" + [m1 m2] + (->> (select-keys m1 (keys m2)) + (merge m2))) diff --git a/test/cljc/automaton_core/utils/keyword_test.cljc b/test/cljc/automaton_core/utils/keyword_test.cljc index 1efc55db..1e5583fe 100644 --- a/test/cljc/automaton_core/utils/keyword_test.cljc +++ b/test/cljc/automaton_core/utils/keyword_test.cljc @@ -3,12 +3,12 @@ #?(:clj [clojure.test :refer [deftest is testing]] :cljs [cljs.test :refer [deftest is testing] :include-macros true]))) -(deftest sanitize-key-test - (testing "Basic case" (is (= :hello (sut/sanitize-key :hello)))) - (testing "capital letters turned into lower case" (is (= :hello (sut/sanitize-key :HeLLo)))) - (testing "_ turned into -" (is (= :hello-world (sut/sanitize-key :hello_world)))) - (testing ". turned into -" (is (= :hello-world (sut/sanitize-key :hello-world)))) - (testing "Works also on strings" (is (= :hello-my-world (sut/sanitize-key "hello.MY_wOrLd"))))) +(deftest keywordize-test + (testing "Basic case" (is (= :hello (sut/keywordize :hello)))) + (testing "capital letters turned into lower case" (is (= :hello (sut/keywordize :HeLLo)))) + (testing "_ turned into -" (is (= :hello-world (sut/keywordize :hello_world)))) + (testing ". turned into -" (is (= :hello-world (sut/keywordize :hello-world)))) + (testing "Works also on strings" (is (= :hello-my-world (sut/keywordize "hello.MY_wOrLd"))))) (deftest sanitize-map-keys-test (testing "Basic case"