Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 97 lines (83 sloc) 3.656 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
(ns leiningen.help
  "Display a list of tasks or help for a given task."
  (:use [leiningen.util.ns :only [namespaces-matching]])
  (:require [clojure.string :as string]
            [clojure.java.io :as io]))

(def tasks (->> (namespaces-matching "leiningen")
                (filter #(re-find #"^leiningen\.(?!core|util)[^\.]+$" (name %)))
                (distinct)
                (sort)))

(defn get-arglists [task]
  (for [args (or (:help-arglists (meta task)) (:arglists (meta task)))]
    (vec (remove #(= 'project %) args))))

(def help-padding 3)

(defn- formatted-docstring [command docstring padding]
  (apply str
    (replace
      {\newline
       (apply str
         (cons \newline (repeat (+ padding (count command)) \space)))}
      docstring)))

(defn- formatted-help [command docstring longest-key-length]
  (let [padding (+ longest-key-length help-padding (- (count command)))]
    (format (str "%1s" (apply str (repeat padding \space)) "%2s")
      command
      (formatted-docstring command docstring padding))))

(defn- get-subtasks-and-docstrings-for [task]
  (into {}
    (map (fn [subtask]
           (let [m (meta subtask)]
             [(str (:name m)) (:doc m)]))
         (:subtasks (meta task)))))

(defn subtask-help-for
  [task-ns task]
  (let [subtasks (get-subtasks-and-docstrings-for task)]
    (if (empty? subtasks)
      nil
      (let [longest-key-length (apply max (map count (keys subtasks)))
            help-fn (ns-resolve task-ns 'help)]
        (string/join "\n"
          (concat ["\n\nSubtasks available:"]
                  (for [[subtask doc] subtasks]
                    (formatted-help subtask doc longest-key-length))))))))

(defn- resolve-task [task-name]
  (let [task-ns (doto (symbol (str "leiningen." task-name)) require)
        task (ns-resolve task-ns (symbol task-name))]
    [task-ns task]))

(defn static-help [name]
  (when-let [reader (io/resource (format "leiningen/help/%s" name))]
    (slurp reader)))

(defn help-for
  "Help for a task is stored in its docstring, or if that's not present
in its namespace."
  [task-name]
  (let [[task-ns task] (resolve-task task-name)
        help-fn (ns-resolve task-ns 'help)]
    (str (or (and (not= task-ns 'leiningen.help) help-fn (help-fn))
             (:doc (meta task))
             (:doc (meta (find-ns task-ns))))
         (subtask-help-for task-ns task)
         (when (some seq (get-arglists task))
           (str "\n\nArguments: " (pr-str (get-arglists task)))))))

;; affected by clojure ticket #130: bug of AOT'd namespaces losing metadata
(defn help-summary-for [task-ns]
  (try (let [task-name (last (.split (name task-ns) "\\."))
             ns-summary (:doc (meta (find-ns (doto task-ns require))))
             first-line (first (.split (help-for task-name) "\n"))]
         ;; Use first line of task docstring if ns metadata isn't present
         (str task-name (apply str (repeat (- 12 (count task-name)) " "))
              (or ns-summary first-line)))
       (catch Throwable e
         (binding [*out* *err*]
           (str task-ns " Problem loading: " (.getMessage e))))))

(defn help
  "Display a list of tasks or help for a given task.

Also provides readme, tutorial, news, sample, deploying and copying documentation."
  ([task] (println (or (static-help task) (help-for task))))
  ([]
     (println "Leiningen is a tool for working with Clojure projects.\n")
     (println "Several tasks are available:")
     (doseq [task-ns tasks]
       (println (help-summary-for task-ns)))
     (println "\nRun lein help $TASK for details.")
     (println "See also: readme, tutorial, copying, sample, deploying and news.")))
Something went wrong with that request. Please try again.