Commits

Howard Lewis Ship committed 249c358

Make use of io.aviso:pretty to present exceptions while running tasks

Comments (0)

Files changed (1)

clojuresque-runtime/src/main/resources/clojuresque/cli.clj

-(ns clojuresque.cli)
+(ns clojuresque.cli
+  (:use io.aviso.exception))
 
 (defn- str-cut
   [s n]
   -h, --help or -? stop the parsing and trigger the printing of the usage
   message and thunk is not called.
 
-  thunk is called with a map of option-value pairs found on the command line."
+  thunk is called with a map of option-value pairs found on the command line.
+  
+  On exception, a formatted exception report is written to *err* and the
+  value false is returned."
   [args description specs thunk]
-  (let [[options soptions]
-        (reduce (fn [[opts sopts] spec]
-                  (let [lopt  (name (first spec))
-                        sopt  (second spec)
-                        sopt  (if (symbol? sopt) (name sopt) nil)
-                        [lopt sopt type]
-                        (if (.endsWith lopt "?")
-                          [(str-cut lopt 1) sopt :flag]
-                          [lopt             sopt :option])]
-                    (vector (assoc opts lopt type)
-                            (assoc sopts sopt lopt))))
-                [{} {}]
-                (filter vector? specs))
-        rest-arg (when (symbol? (last specs)) (name (last specs)))]
-    (loop [args   (seq args)
-           argmap (hash-map)]
-      (let [arg (first args)]
-        (cond
-          (nil? args)
-          (if-not rest-arg
-            (thunk argmap)
-            (throw (Exception. "Missing command line arguments")))
+  (try
+    (let [[options soptions]
+          (reduce (fn [[opts sopts] spec]
+                    (let [lopt  (name (first spec))
+                          sopt  (second spec)
+                          sopt  (if (symbol? sopt) (name sopt) nil)
+                          [lopt sopt type]
+                          (if (.endsWith lopt "?")
+                            [(str-cut lopt 1) sopt :flag]
+                            [lopt             sopt :option])]
+                      (vector (assoc opts lopt type)
+                              (assoc sopts sopt lopt))))
+                  [{} {}]
+                  (filter vector? specs))
+          rest-arg (when (symbol? (last specs)) (name (last specs)))]
+      (loop [args   (seq args)
+             argmap (hash-map)]
+        (let [arg (first args)]
+          (cond
+            (nil? args)
+            (if-not rest-arg
+              (thunk argmap)
+              (throw (Exception. "Missing command line arguments")))
 
-          (some #{arg} ["-h" "--help" "-?"])
-          (print-usage description specs)
+            (some #{arg} ["-h" "--help" "-?"])
+            (print-usage description specs)
 
-          (= arg "--")
-          (if rest-arg
-            (thunk (assoc argmap rest-arg (rest args)))
-            (throw (Exception.  "Unexpected command line arguments")))
+            (= arg "--")
+            (if rest-arg
+              (thunk (assoc argmap rest-arg (rest args)))
+              (throw (Exception.  "Unexpected command line arguments")))
 
-          (.startsWith arg "--")
-          (let [option (subs arg 2)]
-            (condp = (get options option)
-              :flag   (recur (next args) (assoc argmap option true))
-              :option (if-let [value (second args)]
-                        (recur (nthnext args 2) (assoc argmap option value))
-                        (throw
-                          (Exception.  (str "Missing value for option: " arg))))
-              nil     (throw (Exception. (str "Unknown option: " option)))))
+            (.startsWith arg "--")
+            (let [option (subs arg 2)]
+              (condp = (get options option)
+                :flag   (recur (next args) (assoc argmap option true))
+                :option (if-let [value (second args)]
+                          (recur (nthnext args 2) (assoc argmap option value))
+                          (throw
+                            (Exception.  (str "Missing value for option: " arg))))
+                nil     (throw (Exception. (str "Unknown option: " option)))))
 
-          (.startsWith arg "-")
-          (let [option (subs arg 1)]
-            (if-let [loption (get soptions option)]
-              (recur (cons (str "--" loption) (rest args)) argmap)
-              (throw (Exception. (str "Unknown option: " option)))))
+            (.startsWith arg "-")
+            (let [option (subs arg 1)]
+              (if-let [loption (get soptions option)]
+                (recur (cons (str "--" loption) (rest args)) argmap)
+                (throw (Exception. (str "Unknown option: " option)))))
 
-          :else
-          (if rest-arg
-            (thunk (assoc argmap rest-arg args))
-            (throw (Exception.  "Unexpected command line arguments"))))))))
+            :else
+            (if rest-arg
+              (thunk (assoc argmap rest-arg args))
+              (throw (Exception.  "Unexpected command line arguments")))))))
+    (catch Throwable t
+      (binding [*out* *err*]
+        (write-exception t)
+        (flush))
+      ;; Return false to indicate failure
+      false)))
 
 (defmacro with-command-line
   "Parses the command line arguments given according to the specifications.