Skip to content

Commit

Permalink
WIP interactive prompts for values
Browse files Browse the repository at this point in the history
  • Loading branch information
snorremd committed Jul 13, 2019
1 parent 29fcd3c commit 4293ea2
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 23 deletions.
67 changes: 45 additions & 22 deletions src/cli_matic/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@
:args (s/cat :parms ::S/mapOfCliParams)
:ret (s/coll-of string?))


(defn default-prompt
[option]
(update-in option
[:interactive :prompt]
#(if (nil? %)
(str (:as option) " ("
(:option option)
(when (:default option)
", default: "
(:default option))
"): ")
%)))


(defn map-keys
""
[options f]
(into {} (map (fn [opt] [(:option opt) (f opt)]) options)))

(defn parse-cmds-with-defaults
"Parses a command line with environment defaults.
Expand All @@ -150,27 +170,29 @@
"

[cmt-options argv in-order? fn-env]
[cmt-options argv in-order? fn-env fn-int]
(let [cli-cmd-options (U/cm-opts->cli-opts cmt-options)
env-options (filter :env cmt-options)
argv+ (if (not (empty? env-options))
;; I have env variables
(let [parse1 (parse-opts argv cli-cmd-options
:in-order in-order?
::no-defaults true)
set-keys-in (set (keys (:options parse1)))
missing-cmt-options (filter (complement set-keys-in) env-options)
map-missing-keys (into {}
(map
(fn [{:keys [option env]}]
[option (fn-env env)])
missing-cmt-options))]
(into (mk-fake-args map-missing-keys) argv))

;; no env variables - we are good
argv)]

(parse-opts argv+ cli-cmd-options :in-order in-order?)))
interactive-options (if (P/tty?) (filter :interactive cmt-options) [])
parsed-opts (parse-opts argv cli-cmd-options
:in-order in-order?
::no-defaults true)
;;_ (clojure.pprint/pprint parsed-opts)
parsed-interactive (-> (keys (:options parsed-opts))
set
complement
(filter (->> interactive-options
(map #(assoc % :option (keyword (:option %))))))
(map-keys (comp fn-int :interactive)))
parsed-env (-> (keys (merge (:options parsed-opts)
parsed-interactive))
set
complement
(filter env-options)
(map-keys (comp fn-env :env)))
argv+ (mk-fake-args (merge parsed-interactive parsed-env))]
(-> (concat argv+ argv)
(parse-opts cli-cmd-options :in-order in-order?))))

(s/fdef
parse-cmds-with-defaults
Expand All @@ -195,7 +217,7 @@
"
[config canonical-subcommand subcommand-parms]
(let [cmt-options (U/get-options-for config canonical-subcommand)
parsed-cmd-opts (parse-cmds-with-defaults cmt-options subcommand-parms false P/read-env)
parsed-cmd-opts (parse-cmds-with-defaults cmt-options subcommand-parms false P/read-env P/read-interactive)
cmd-args (:arguments parsed-cmd-opts)

;; capture positional parms
Expand All @@ -207,7 +229,7 @@
(pos? (count positional-parms))
(let [addl-args (mk-fake-args positional-parms)
newcmdline (into subcommand-parms addl-args)]
(parse-cmds-with-defaults cmt-options newcmdline false P/read-env))
(parse-cmds-with-defaults cmt-options newcmdline false P/read-env P/read-interactive))

:else
parsed-cmd-opts)))
Expand Down Expand Up @@ -335,7 +357,7 @@

(let [gl-options (U/get-options-for config nil)
;_ (prn "Cmdline" cmdline)
parsed-gl-opts (parse-cmds-with-defaults gl-options argv true P/read-env) ;(parse-opts cmdline cli-gl-options :in-order true)
parsed-gl-opts (parse-cmds-with-defaults gl-options argv true P/read-env P/read-interactive) ;(parse-opts cmdline cli-gl-options :in-order true)
missing-gl-opts (errors-for-missing-mandatory-args
(U/get-options-for config nil)
parsed-gl-opts {})
Expand Down Expand Up @@ -407,6 +429,7 @@
:opts ::S/climatic-cfg)
:ret ::S/lineParseResult)


(defn assert-unique-values
"Check that all values are unique.
name is the area of the configuration
Expand Down
15 changes: 15 additions & 0 deletions src/cli_matic/platform.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@
[var]
(System/getenv var))

(defn read-interactive
"Reads value from tty.
If masked? is true masks user input with *"
[{:keys [prompt masked?]}]
(let [console (System/console)]
(print prompt)
(flush)
(if masked?
(apply str (.readPassword console))
(read-line))))

(defn tty?
[]
(some? (System/console)))

(defn exit-script
"Terminates execution with a return value."
[retval]
Expand Down
16 changes: 16 additions & 0 deletions src/cli_matic/platform.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"
(:require [planck.core :as plk]
[planck.environ :as plkenv]
[planck.io :as plkio]
[cljs.reader :as csrdr]
[clojure.string :as str]))

Expand All @@ -19,6 +20,21 @@
(let [kw (keyword (str/lower-case var))]
(get plkenv/env kw nil)))


(defn read-interactive
"Reads value from tty.
If masked? is true masks user input with *"
[masked?]
(if masked?
(plk/read-password)
(plk/read-line)))

(defn tty?
[]
(and (plkio/tty? plk/*in*)
(plkio/tty? plk/*out*)))


(defn exit-script
"Terminates execution with a return value.
Expand Down
9 changes: 8 additions & 1 deletion src/cli_matic/specs.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,18 @@

(s/def ::env ::existing-string)

(s/def ::masked? boolean?)

(s/def ::prompt string?)

(s/def ::interactive
(s/keys :req-opt [::masked? ::prompt]))

(s/def ::spec some?) ; \TODO how do we know it's a valid spec?

(s/def ::climatic-option
(s/keys :req-un [::option ::as ::type]
:opt-un [::short ::default ::env ::spec]))
:opt-un [::short ::default ::env ::spec ::interactive]))

;; CLI-matic configuration
(s/def ::description (s/or :a-string ::existing-string
Expand Down

0 comments on commit 4293ea2

Please sign in to comment.