-
Notifications
You must be signed in to change notification settings - Fork 26
/
configuring.clj
100 lines (84 loc) · 3.6 KB
/
configuring.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
(ns de.otto.tesla.stateful.configuring
"This component is responsible for loading the configuration."
(:require [com.stuartsierra.component :as component]
[clojurewerkz.propertied.properties :as p]
[clojure.tools.logging :as log]
[clojure.java.io :as io]
[de.otto.tesla.util.keyword :as kwutil]
[environ.core :as env :only [env]]
[de.otto.tesla.util.env_var_reader :only [read-env-var]]
[de.otto.tesla.util.sanitize :as san])
(:import (java.io PushbackReader)))
(defn deep-merge
"Recursively merges maps. If vals are not maps, the last value wins."
[& vals]
(if (every? map? vals)
(apply merge-with deep-merge vals)
(last vals)))
(defn- load-properties-from-resource [resource]
(kwutil/sanitize-keywords
(p/properties->map
(p/load-from resource) false)))
(defn resolve-file [name type]
(cond
(= :resource type) (io/resource name)
(and (= :file type) (.exists (io/file name))) (io/file name)
(and (= :resource-or-file type) (io/resource name)) (io/resource name)
(and (= :resource-or-file type) (.exists (io/file name))) (io/file name)))
(defn- load-properties [name type]
(when-let [resource (resolve-file name type)]
(load-properties-from-resource resource)))
(defn- load-edn [name type]
(when-let [resource (resolve-file name type)]
(log/debugf "Reading %s" name)
(-> resource
(io/reader)
(PushbackReader.)
(read))))
(defn load-merge [load-fn merge-fn ending runtime-config]
(let [default-cfg-name (or (:default-cfg-file-name runtime-config) "default")
defaults (load-fn (str default-cfg-name ending) :resource)
application (load-fn (or (:config-file env/env) (str "application" ending)) :resource-or-file)
local (load-fn (str "local" ending) :resource)
private (load-fn (str "private" ending) :resource)
configs (filter some? [defaults application local private runtime-config])]
(apply merge-fn configs)))
(defn load-config-from-edn-files [runtime-config]
(load-merge load-edn deep-merge ".edn" runtime-config))
(defn load-config-from-properties-files [runtime-config]
(let [loaded (load-merge load-properties merge ".properties" runtime-config)]
(if (:merge-env-to-properties-config runtime-config)
(merge loaded env/env)
loaded)))
(defn load-and-merge [runtime-config]
(if-not (:property-file-preferred runtime-config)
(load-config-from-edn-files runtime-config)
(load-config-from-properties-files runtime-config)))
;; Load config on startup.
(defrecord Configuring [runtime-config]
component/Lifecycle
(start [self]
(log/info "-> loading configuration.")
(log/info runtime-config)
(let [config (load-and-merge runtime-config)]
(log/info "-> using configuration:\n" (with-out-str (clojure.pprint/pprint (san/hide-passwds config))))
(assoc self :config config
:version (load-properties "version.properties" :resource))))
(stop [self]
(log/info "<- stopping configuration.")
self))
(defn new-config [runtime-config]
(map->Configuring {:runtime-config runtime-config}))
;; The hostname and port visble from the outside are different for
;; different environments.
;; These methods default to Marathon defaults.
(defn external-hostname [{:keys [config]}]
(or (:host-name config)
(:host env/env) (:host-name env/env) (:hostname env/env)
"localhost"))
(defn server-port [config]
(:server-port config))
;; see above
(defn external-port [{:keys [config]}]
(or (server-port config)
(:port0 env/env) (:host-port env/env) (:server-port env/env)))