Search code examples
clojureclojure-contrib

How to show error on missing parameters for options?


I'm an absolute Clojure beginner and I'm trying to build a CLI app using the clojure.tools.cli library.

My problem is that I can't show any error when an option is not provided with required parameter.

What I want:

$ java -jar test.jar -m SAMPLE
Given file: SAMPLE

$ java -jar test.jar -m
ERROR: Please provide a file

What happens:

$ java -jar test.jar -m SAMPLE
Given file: SAMPLE

$ java -jar test.jar -m

$

It doesn't show anything.

Here is my code:

(ns obmed-clj.core
  (:require [clojure.tools.cli :refer [parse-opts]])
  (:gen-class))

(def cli-options
  [["-m" "--menu FILE" "Provide menu file path"
    :parse-fn #(if (nil? %) 
                   (println "ERROR: Please provide a file") 
                   %)
    :validate-fn #(println "Given file:" %)]])

(defn -main [& args]
  (parse-opts args cli-options))

Solution

  • You are abusing the -fn arguments here a little. Their use is to convert the "string" (in your case, since you have "--menu FILE") and then do additional validation on that (but rather use :validate [fn msg] instead). So e.g.:

    user=> (def cli-opts [["-m" "--menu FILE" "menu file" 
                :parse-fn #(java.io.File. %) 
                :validate [#(.exists %) "file must exist"]]])
    #'user/cli-opts
    

    Missing argument:

    user=> (parse-opts ["-m"] cli-opts)
    {:arguments [],
     :errors ["Missing required argument for \"-m FILE\""],
     :options {},
     :summary "  -m, --menu FILE  menu file"}
    

    File not existing:

    user=> (parse-opts ["-m" "XXX"] cli-opts)
    {:arguments [],
     :errors ["Failed to validate \"-m XXX\": file must exist"],
     :options {},
     :summary "  -m, --menu FILE  menu file"}
    

    All is well:

    user=> (parse-opts ["-m" "/etc/hosts"] cli-opts)
    {:arguments [],
     :errors nil,
     :options {:menu #<java.io.File@34d63c80 /etc/hosts>},
     :summary "  -m, --menu FILE  menu file"}