Skip to content

Multiple options before subcommands #106

@sh54

Description

@sh54

I want to run a program via:

my-program --config config.edn --config other-config.edn dothis --hello world

If I saw this in the wild I would expect this to run my-program with subcommand dothis with the options {:config ["config.edn" "other-config.edn"], :hello "world"}.

However if I setup a dispatch table with the root spec resembling {:config {:coerce []}} then the bit dothis gets interpreted as another value to add to option :config rather than getting recognized as the subcommand to run.

Here is an example program. The comments have examples of dispatch calls and their actual results, along with what I would expect them to return if I think the result is incorrect.

(ns example
  (:require [babashka.cli :as cli]))

(def global-spec {:config  {:desc "Config edn file to use"
                            :coerce []}
                  :verbose {:coerce :boolean}})
(def dns-spec {})
(def dns-get-spec {})

(def table
  [{:cmds []            :fn identity :spec global-spec}
   {:cmds ["dns"]       :fn identity :spec dns-spec}
   {:cmds ["dns" "get"] :fn identity :spec dns-get-spec}])

(defn -main
  [& args]
  (prn (cli/dispatch table (vec args))))

(when (= *file* (System/getProperty "babashka.file"))
  (apply -main *command-line-args*))

(comment
  ;; Correct
  (cli/dispatch table ["--config" "config-dev.edn"])
  #_ {:dispatch [], :opts {:config ["config-dev.edn"]}, :args nil}

  ;; Correct
  (cli/dispatch table ["--config" "config-dev.edn" "--config" "other.edn"])
  #_ {:dispatch [],
      :opts {:config ["config-dev.edn" "other.edn"]},
      :args nil}

  ;; Correct
  (cli/dispatch table ["--config" "config-dev.edn" "--config" "other.edn" "--verbose"])
  #_ {:dispatch [],
      :opts {:config ["config-dev.edn" "other.edn"], :verbose true},
      :args nil}

  ;; Incorrect
  (cli/dispatch table ["--config" "config-dev.edn" "--config" "other.edn" "dns"])
  #_ {:dispatch [], :opts {:config ["config-dev.edn" "other.edn" "dns"]}, :args nil}
  ;; Expected
  #_ {:dispatch ["dns"], :opts {:config ["config-dev.edn" "other.edn"]}, :args nil}

  ;; Incorrect
  (cli/dispatch table ["--config" "config-dev.edn" "--config" "other.edn" "dns" "get"])
  #_ {:dispatch [],
      :opts {:config ["config-dev.edn" "other.edn" "dns" "get"]},
      :args nil}
  ;; Expected
  #_ {:dispatch ["dns" "get"],
      :opts {:config ["config-dev.edn" "other.edn"]},
      :args nil}

  ;; Correct - the --verbose flag seems to break up everything getting dragged into :config
  (cli/dispatch table ["--config" "config-dev.edn" "--config" "other.edn" "--verbose" "dns" "get"])
  #_ {:dispatch ["dns" "get"],
      :opts {:config ["config-dev.edn" "other.edn"], :verbose true},
      :args nil}

  ;; Incorrect
  (cli/dispatch table ["--config" "config-dev.edn" "--verbose" "--config" "other.edn" "dns" "get"])
  #_ {:dispatch [],
      :opts {:config ["config-dev.edn" "other.edn" "dns" "get"], :verbose true},
      :args nil}
  ;; Expected
  #_ {:dispatch ["dns" "get"],
      :opts {:config ["config-dev.edn" "other.edn"], :verbose true},
      :args nil}

  ;; Incorrect
  (cli/dispatch table ["--config" "config-dev.edn" "--config=other.edn" "dns" "get"])
  #_ {:dispatch [],
      :opts {:config ["config-dev.edn" "other.edn" "dns" "get"]},
      :args nil}
  ;; Expected
  #_ {:dispatch ["dns" "get"],
      :opts {:config ["config-dev.edn" "other.edn"]},
      :args nil}

  ;; Correct
  (cli/dispatch table ["dns" "get"])
  #_ {:dispatch ["dns" "get"], :opts {}, :args nil}

  )

This is tested with 0.8.60

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions