Tools for working with command line arguments.
Latest stable release: 0.3.5
Leiningen dependency information:
[org.clojure/tools.cli "0.3.5"]
Maven dependency information:
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.cli</artifactId>
<version>0.3.5</version>
</dependency>
The 0.3.x series of tools.cli features a new flexible API, better adherence to GNU option parsing conventions, and ClojureScript support.
The function clojure.tools.cli/cli
has been superseded by
clojure.tools.cli/parse-opts
, and should not be used in new programs.
The previous function will remain for the forseeable future. It has also been
adapted to use the new tokenizer, so upgrading is still worthwhile even if you
are not ready to migrate to parse-opts
.
(ns my.program
(:require [clojure.tools.cli :refer [parse-opts]])
(:gen-class))
(def cli-options
;; An option with a required argument
[["-p" "--port PORT" "Port number"
:default 80
:parse-fn #(Integer/parseInt %)
:validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]]
;; A non-idempotent option
["-v" nil "Verbosity level"
:id :verbosity
:default 0
:assoc-fn (fn [m k _] (update-in m [k] inc))]
;; A boolean option defaulting to nil
["-h" "--help"]])
(defn -main [& args]
(parse-opts args cli-options))
Execute the command line:
my-program -vvvp8080 foo --help --invalid-opt
to produce the map:
{:options {:port 8080
:verbosity 3
:help true}
:arguments ["foo"]
:summary " -p, --port PORT 80 Port number
-v Verbosity level
-h, --help"
:errors ["Unknown option: \"--invalid-opt\""]}
Note that exceptions are not thrown on parse errors, so errors must be
handled explicitly after checking the :errors
entry for a truthy value.
Please see the example program for a more detailed example
and refer to the docstring of parse-opts
for comprehensive documentation:
http://clojure.github.io/tools.cli/index.html#clojure.tools.cli/parse-opts
In accordance with the GNU Program Argument Syntax Conventions, two features have been added to the options tokenizer:
Short options may be grouped together.
For instance, -abc
is equivalent to -a -b -c
. If the -b
option
requires an argument, the same -abc
is interpreted as -a -b "c"
.
Long option arguments may be specified with an equals sign.
--long-opt=ARG
is equivalent to --long-opt "ARG"
.
If the argument is omitted, it is interpreted as the empty string.
e.g. --long-opt=
is equivalent to --long-opt ""
Large programs are often divided into subcommands with their own sets of
options. To aid in designing such programs, clojure.tools.cli/parse-opts
accepts an :in-order
option that directs it to stop processing arguments at
the first unrecognized token.
For instance, the git
program has a set of top-level options that are
unrecognized by subcommands and vice-versa:
git --git-dir=/other/proj/.git log --oneline --graph
By default, clojure.tools.cli/parse-opts
interprets this command line as:
options: [[--git-dir /other/proj/.git]
[--oneline]
[--graph]]
arguments: [log]
When :in-order is true however, the arguments are interpreted as:
options: [[--git-dir /other/proj/.git]]
arguments: [log --oneline --graph]
Note that the options to log
are not parsed, but remain in the unprocessed
arguments vector. These options could be handled by another call to
parse-opts
from within the function that handles the log
subcommand.
parse-opts
returns a minimal options summary string:
-p, --port NUMBER 8080 Required option with default
--host HOST localhost Short and long options may be omitted
-d, --detach Boolean option
-h, --help
This may be inserted into a larger usage summary, but it is up to the caller.
If the default formatting of the summary is unsatisfactory, a :summary-fn
may be supplied to parse-opts
. This function will be passed the sequence
of compiled option specification maps and is expected to return an options
summary.
The default summary function clojure.tools.cli/summarize
is public and may
be useful within your own :summary-fn
for generating the default summary.
There is a new option entry :validate
, which takes a tuple of
[validation-fn validation-msg]
. The validation-fn receives an option's
argument after being parsed by :parse-fn
if it exists.
["-p" "--port PORT" "A port number"
:parse-fn #(Integer/parseInt %)
:validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]]
If the validation-fn returns a falsy value, the validation-msg is added to the errors vector.
Instead of throwing errors, parse-opts
collects error messages into a vector
and returns them to the caller. Unknown options, missing required arguments,
validation errors, and exceptions thrown during :parse-fn
are all added to
the errors vector.
Correspondingly, parse-opts
returns the following map of values:
{:options A map of default options merged with parsed values from the command line
:arguments A vector of unprocessed arguments
:summary An options summary string
:errors A vector of error messages, or nil if no errors}
During development, parse-opts asserts the uniqueness of option :id
,
:short-opt
, and :long-opt
values and throws an error on failure.
The cljs.tools.cli
namespace is available for use in ClojureScript programs!
Both parse-opts
and summarize
have been ported, and have complete feature
parity with their Clojure counterparts.
ClojureScript Versions 0.0-2080
and above are supported, but earlier
versions are likely to work as well.
(ns cli-example.core
(:require [cli-example.server :as server]
[clojure.string :as string]
[clojure.tools.cli :refer [parse-opts]])
(:import (java.net InetAddress))
(:gen-class))
(def cli-options
[;; First three strings describe a short-option, long-option with optional
;; example argument description, and a description. All three are optional
;; and positional.
["-p" "--port PORT" "Port number"
:default 80
:parse-fn #(Integer/parseInt %)
:validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]]
["-H" "--hostname HOST" "Remote host"
:default (InetAddress/getByName "localhost")
;; Specify a string to output in the default column in the options summary
;; if the default value's string representation is very ugly
:default-desc "localhost"
:parse-fn #(InetAddress/getByName %)]
;; If no required argument description is given, the option is assumed to
;; be a boolean option defaulting to nil
[nil "--detach" "Detach from controlling process"]
["-v" nil "Verbosity level; may be specified multiple times to increase value"
;; If no long-option is specified, an option :id must be given
:id :verbosity
:default 0
;; Use assoc-fn to create non-idempotent options
:assoc-fn (fn [m k _] (update-in m [k] inc))]
["-h" "--help"]])
(defn usage [options-summary]
(->> ["This is my program. There are many like it, but this one is mine."
""
"Usage: program-name [options] action"
""
"Options:"
options-summary
""
"Actions:"
" start Start a new server"
" stop Stop an existing server"
" status Print a server's status"
""
"Please refer to the manual page for more information."]
(string/join \newline)))
(defn error-msg [errors]
(str "The following errors occurred while parsing your command:\n\n"
(string/join \newline errors)))
(defn validate-args
"Validate command line arguments. Either return a map indicating the program
should exit (with a error message, and optional ok status), or a map
indicating the action the program should take and the options provided."
[args]
(let [{:keys [options arguments errors summary]} (parse-opts args cli-options)]
(cond
(:help options) ; help => exit OK with usage summary
{:exit-message (usage summary) :ok? true}
errors ; errors => exit with description of errors
{:exit-message (error-msg errors)}
;; custom validation on arguments
(and (= 1 (count arguments))
(#{"start" "stop" "status"} (first arguments)))
{:action (first arguments) :options options}
:else ; failed custom validation => exit with usage summary
{:exit-message (usage summary)})))
(defn exit [status msg]
(println msg)
(System/exit status))
(defn -main [& args]
(let [{:keys [action options exit-message ok?]} (validate-args args)]
(if exit-message
(exit (if ok? 0 1) exit-message)
(case action
"start" (server/start! options)
"stop" (server/stop! options)
"status" (server/status! options)))))
summarize
in cljs after renaming during TCLI-36 below
TCLI-85.summarize
via expanded docstring and make both of the
functions it calls public so it is easier to build your own :summary-fn
.
TCLI-36.:missing
to option specification to produce the given error message
if the option is not provided (and has no default value).
TCLI-12:strict
to parse-opts
:
If true, treats required option arguments that match other options as a
parse error (missing required argument).
TCLI-10:no-defaults
to parse-opts
:
Returns sequence of options that excludes defaulted ones. This helps
support constructing options from multiple sources (command line, config file).get-default-options
:
Returns sequence of options that have defaults specified.:in-order
processes arguments up to the first unknown option;
A warning is displayed when unknown options are encountered.parse-opts
and summarize
to supersede cli
,
addressing TCLI-3,
TCLI-4, and
TCLI-6parse-opts
and summarize
, available in
cljs.tools.cli
.cli
function to
https://github.com/clojure/tools.cli/wiki/Documentation-for-0.2.4Copyright (c) Rich Hickey and contributors. All rights reserved.
The use and distribution terms for this software are covered by the Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can be found in the file epl.html at the root of this distribution. By using this software in any fashion, you are agreeing to be bound by the terms of this license.
You must not remove this notice, or any other, from this software.
Can you improve this documentation? These fine people already did:
Gareth Jones, Sean Corfield, guns, Aaron Bedra & Stuart HallowayEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close