这是一个修辞问题,因为我知道 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})))