这其实是一个修辞问题,因为在我看来,tools.cli并不能对位置参数做任何事情,只是将它们作为字符串向量传递给库的用户。但我还是会分享我的用例。
我正在编写一个工具,它可以将文件从一个目录复制到另一个目录。它接受两个位置参数,源和目标。目前我的代码包含了两次输入验证和解析,第一次是为工具使用tools.cli,然后是第二次在我的自己的函数parse-arguments
中处理参数。如果能这两件事一步到位就不错了。
请查看以下代码示例。
(ns multi-machine-rsync.cli
(:require [clojure.tools.cli :as cli]
[clojure.java.io :as io]
[clojure.string :as string]))
(defn read-settings
[path]
(read-string (slurp path)))
(def cli-options
[["-h" "--help" "Show this help text"]
["-s" "--settings SETTING-FILE" "Path to the settings file."
:parse-fn read-settings
:default "settings.edn"]])
(defn usage
[options-summary]
(string/join
\newline
["Copies a directory from one place to another in a common"
"directory structure using multiple machines."
""
"Usage: multi-machine-rsync [OPTIONS] SOURCE DESTINATION"
""
"Options:"
options-summary]))
(defn parse-arguments
"Parse and 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 [arguments options errors summary]} (cli/parse-opts args cli-options)
[source destination] (map io/file arguments)]
(cond
(:help options) {:exit-message (usage summary) :ok? true}
errors {:exit-message errors}
(nil? source) {:exit-message "First positional argument SOURCE not given."}
(nil? destination) {:exit-message "Second positional argument DESTINATION not given."}
(not (.exists source)) {:exit-message "Source directory does not exist."}
(not (.exists destination)) {:exit-message "Destination directory does not exist."}
:else {:options options
:source source
:destination destination})))