A simple DSL for building command-line interfaces with trees of subcommands.
This library wraps the org.clojure/tools.cli
library for option parsing.
Library releases are published on Clojars.
To use this version with Leiningen, add the following dependency to your project definition:
[mvxcvi/directive "0.4.2"]
The command
macro lets you declare a tree of subcommands, each of which can
have its own options, arguments, and initialization function. Leaf commands
specify an action to take when invoked.
(require '[mvxcvi.directive :refer [command execute]])
(def commands
; Commands start with the command name, followed by usage information.
(command "my-tool [global opts] <command> [command args]"
; Second is a longer description string.
"Command-line tool for my awesome project."
; Next are option specs, passed to clojure.tools.cli.
["--config" "Set path to tool configuration."
:default my-config/default-path]
["-v" "--verbose" "Show extra debugging messages." :default false]
["-h" "--help" "Show usage information."]
; NOTE: don't use `:default false` for help flags, because it will break
; the implicit 'cmd help <args>' handler.
; Functions may be given as symbolic references like this or defined inline
; as below.
(init my-config/initialize)
; Subcommands are just nested `command` nodes.
(command "config <type>"
"Show configuration information."
(command "dump"
"Prints out a raw version of the configuration map."
[nil "--pretty" "Formats the info over multiple lines for easier viewing."]
; Leaf commands have actions, functions which run on the option map and
; any non-option arguments.
(action [opts args]
(if (:pretty opts)
(pprint opts args)
(prn opts args)))))
(command "foo <action> [args]"
"Low-level commands dealing with foos."
(init [opts]
(assoc opts :foo true))
(action do-foo-action))))
(defn -main [& args]
(execute commands args))
Initialization functions are given the current option map and must return an updated version of the map in addition to causing any necessary side-effects. Actions take the option map and a vector of the remaining arguments. Either may be specified as a symbol or as an inline function body.
This is free and unencumbered software released into the public domain. See the UNLICENSE file for more information.