#!/Usr/bin/env joker ;; Usage: toolchain-report ;; ;; This tool queries a set of defined packages in your "toolchain" and ;; reports the versions of those packages in a map. There are no ;; command line flags or options for this script. (ns main (:require [joker.os :as os])) ;; The "toolchain" is defined as a vector of maps that define how to ;; query for version. We expect every tool has some command line flag ;; that writes the version info to stdout or stderr, but each tool ;; might format that output in some unique way. Therefore we specify a ;; regular expression pattern that will be used to extract the version ;; from the output. ;; ;; Easiest to show an example: ;; ;; { ;; :key :yarn ; each tool has a unique key ;; :cmd ["yarn" "-v"] ; executing this prints the version ;; :pattern #"(.*)\n" ; this regexp extracts the version # ;; :output :out ; :out = stdout, :err = stderr ;; } ;; ;; The default is to grab everything from stdout up to the first ;; newline '\n', so our example can be shortened: ;; ;; {:key :yarn :cmd ["yarn" "-v"]} ;; (def toolchain [ ;; operating system {:key :os-name :cmd ["clojure" "-e" "(System/getProperty \"os.name\")"] :pattern #"\"(.*)\""} {:key :os-version :cmd ["clojure" "-e" "(System/getProperty \"os.version\")"] :pattern #"\"(.*)\""} {:key :todays-date :cmd ["clojure" "-e" "(.toString (java.time.LocalDate/now))"]} ;; clojure/clojurescript tools {:key :clojure :cmd ["clj" "-Stree"] :pattern #"org.clojure/clojure\s+(.*)\n"} {:key :clojurescript :cmd ["clj" "-Stree"] :pattern #"org.clojure/clojurescript\s+(.*)\n"} {:key :shadow-cljs-jar :cmd ["shadow-cljs" "info"] :pattern #"jar:\s+(.*)\n"} {:key :shadow-cljs-cli :cmd ["shadow-cljs" "info"] :pattern #"cli:\s+(.*)\n"} ;; react native toolchain {:key :expo-cli :cmd ["expo-cli" "-V"]} ;; javascript tools {:key :node :cmd ["node" "-v"]} {:key :yarn :cmd ["yarn" "-v"]} ;; libraries / packages {:key :expo-js :cmd ["yarn" "list"] :pattern #"\s+expo@(.*)\n"} {:key :react :cmd ["yarn" "list"] :pattern #"\s+react@(.*)\n"} {:key :react-native :cmd ["yarn" "list"] :pattern #"\s+react-native@(.*)\n"} {:key :reagent :cmd ["clj" "-Stree"] :pattern #"reagent/reagent\s+(.*)\n"} {:key :re-frame :cmd ["clj" "-Stree"] :pattern #"re-frame/re-frame\s+(.*)\n"} ;; java jdk {:key :jdk-vendor :cmd ["java" "-version"] :output :err :pattern #"(.*)\s+version"} {:key :jdk-version :cmd ["java" "-version"] :output :err :pattern #"version\s+\"(.*)\"\n"} ]) (def sh-memoized (memoize #(apply os/sh %))) (defn check [{:keys [key cmd output pattern] :or {output :out pattern #"(.*)\n"}}] (let [result (try (sh-memoized cmd) (catch Error e {:success nil}))] (if (:success result) {key (-> (re-find pattern (output result)) (get 1))} {key nil}))) (defn print-sorted-keys [m] ;; hack because joker doesn't provide sorted-map (println "{") (doseq [k (sort (keys m))] (printf " %s \"%s\"\n" k (k m))) (println "}")) ;; run all queries and print the result (print-sorted-keys (->> (map check toolchain) (apply merge)))