From fb0b8e595b817ca237dda4d12d8fe23d6a8caebd Mon Sep 17 00:00:00 2001 From: Tobias Crawley Date: Thu, 27 Sep 2012 11:06:12 -0400 Subject: [PATCH] Extract out the lein command finding fns. This makes them available for plugins to use for testing. --- README.md | 14 ++++ src/leinjacker/lein_runner.clj | 60 +++++++++++++++++ test/leinjacker/multiple_leins_runner.clj | 67 ------------------- .../test_multiple_lein_versions.clj | 29 ++++++++ 4 files changed, 103 insertions(+), 67 deletions(-) create mode 100644 src/leinjacker/lein_runner.clj delete mode 100644 test/leinjacker/multiple_leins_runner.clj create mode 100644 test/leinjacker/test_multiple_lein_versions.clj diff --git a/README.md b/README.md index 2c91ac3..066c5db 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,20 @@ leinjacker is a library of utilities for Leiningen plug-in developers. Current since it was renamed between generations. * `abort` - 1.x- and 2.x-compatible way to signal task failure. +4. `leinjacker.lein-runner` has functions for finding and running the `lein` command on the + path for each Leiningen generation. Useful for testing plugins under various Leiningen + versions. It provides: + + * `find-lein-cmd` - looks for `lein` on the $PATH by trying to call it. It takes a + `generation` argument, which should be `1` or `2`. It will then look for a command + called `lein` or `lein` that reports the correct generation when called + with `lein version`. It will memoize the found cmd to `./.lein-commands` to speed + up subsequent calls. This can be disabled via the `memoize?` arg. + * `run-lein` - Will execute the given Leiningen `generation` in `dir` with the given + `args`, returning the result map from the 'clojure.java.shell/sh' call. + + See leinjacker's tests for examples of usage. + ## Usage Just drop the following into your plug-in’s `project.clj`: diff --git a/src/leinjacker/lein_runner.clj b/src/leinjacker/lein_runner.clj new file mode 100644 index 0000000..c453246 --- /dev/null +++ b/src/leinjacker/lein_runner.clj @@ -0,0 +1,60 @@ +(ns leinjacker.lein-runner + "Functions to locate and run the 'lein' command for either lein generation." + (:require [clojure.java.io :as io] + [clojure.java.shell :as shell])) + +(defn- clean-lein-env + "Gets a copy of the system environment tha removes Leiningen environment variables." + [] + (dissoc (into {} (System/getenv)) + "CLASSPATH" "LEIN_JVM_OPTS")) + +(defn- memoize-to-file + "Memoizes the result if not-found-fn under key in filename." + [filename key not-found-fn] + (let [cache-file (io/file filename) + cache (if (.exists cache-file) (read-string (slurp cache-file)) {})] + (or (cache key) + (let [cmd (not-found-fn key)] + (spit cache-file (prn-str (assoc cache key cmd))) + cmd)))) + +(defn- find-lein-cmd* + "Does the work of looking up the lein command without any memoization options." + [generation] + (if-let [cmd (some + (fn [cmd] + (try + (if (.contains (:out (shell/sh cmd "version" :env (clean-lein-env))) + (str "Leiningen " generation ".")) + cmd) + (catch java.io.IOException _))) + ["lein" (str "lein" generation)])] + cmd + (throw (IllegalStateException. + (str "Unable to find Leiningen " generation + " in the path as lein or lein" generation + ". Please make sure it is installed and in your path under one of those names."))))) + +(defn find-lein-cmd + "Attempts to locate the lein command for the given command on the path. +Looks for: lein, lein. If memoize? isn't provided or is true, +the results are cached in ./.lein-commands." + ([generation] + (find-lein-cmd generation true)) + ([generation memoize?] + (if memoize? + (memoize-to-file ".lein-commands" generation find-lein-cmd*) + (find-lein-cmd* generation)))) + +(defn run-lein + "Runs lein for the given generation with args. +:dir and :env options may be specified with kwargs. Returns the result from sh." + [generation & args] + (let [[real-args {:as opts}] (split-with string? args)] + (apply shell/sh (find-lein-cmd generation) + (conj (vec real-args) + :dir (:dir opts) + :env (assoc (merge (clean-lein-env) (:env opts)) + "LEIN_GENERATION" generation))))) + diff --git a/test/leinjacker/multiple_leins_runner.clj b/test/leinjacker/multiple_leins_runner.clj deleted file mode 100644 index b3a71cd..0000000 --- a/test/leinjacker/multiple_leins_runner.clj +++ /dev/null @@ -1,67 +0,0 @@ -(ns leinjacker.multiple-leins-runner - "Runs the tests in the test-projects projects under lein1 and lein2." - {:author "Toby Crawley"} - (:use midje.sweet) - (:require [clojure.java.io :as io] - [clojure.java.shell :as shell] - [leinjacker.utils :as utils] - [leiningen.install :as install])) - -(defn- clean-lein-env - "Gets a copy of the system environment tha removes Leiningen environment variables." - [] - (dissoc (into {} (System/getenv)) - "CLASSPATH" "LEIN_JVM_OPTS")) - -(defn- memoize-to-file - "Memoizes the result if not-found-fn under key in filename." - [filename key not-found-fn] - (let [cache-file (io/file filename) - cache (if (.exists cache-file) (read-string (slurp cache-file)) {})] - (or - (cache key) - (let [cmd (not-found-fn)] - (spit cache-file (prn-str (assoc cache key cmd))) - cmd)))) - -(defn- find-lein-cmd - "Attempts to locate the lein command for the given command on the path. Looks for: lein, lein. The results are cached in .lein-commands" - [generation] - (memoize-to-file ".lein-commands" - generation - #(if-let [cmd (some - (fn [cmd] - (try - (if (.contains (:out (shell/sh cmd "version" :env (clean-lein-env))) - (str "Leiningen " generation ".")) - cmd) - (catch java.io.IOException _))) - ["lein" (str "lein" generation)])] - cmd - (throw (IllegalStateException. (str "Unable to find Leiningen " generation " in the path as lein or lein" generation ". Please make sure it is installed and in your path under one of those names.")))))) - -(defn- run-lein-on-sub-project - "Runs the midje command for the given generation of lein in test-project/" - [generation] - (let [cmd (find-lein-cmd generation)] - (println "\n==> Running" (str \' cmd " midje'") "in test-project/") - (let [result (shell/sh cmd "midje" - :dir "test-project" - :env (assoc (clean-lein-env) - "LEIN_GENERATION" generation))] - (print (:out result)) - (print (:err result)) - (println "==> Done\n") - (:exit result)))) - -;; install leinjacker for the test project to use -(install/install (utils/read-lein-project)) - -(fact "run lein1 tests." - ;; lein1 needs deps resolved to see the installed leinjacker - (shell/sh (find-lein-cmd "1") "deps" :dir "test-project" :env (clean-lein-env)) - (run-lein-on-sub-project "1") => 0) - -(fact "run lein2 tests." - (run-lein-on-sub-project "2") => 0) - diff --git a/test/leinjacker/test_multiple_lein_versions.clj b/test/leinjacker/test_multiple_lein_versions.clj new file mode 100644 index 0000000..adc0901 --- /dev/null +++ b/test/leinjacker/test_multiple_lein_versions.clj @@ -0,0 +1,29 @@ +(ns leinjacker.test-multiple-lein-versions + "Runs the tests in the test-projects projects under lein1 and lein2." + {:author "Toby Crawley"} + (:use midje.sweet) + (:require [leinjacker.utils :as utils] + [leinjacker.lein-runner :as runner] + [leiningen.install :as install])) + +(defn- run-lein-on-sub-project + "Runs the midje command for the given generation of lein in test-project/" + [generation] + (println "\n==> Running 'lein midje' (generation" (str generation \)) "in test-project/") + (let [result (runner/run-lein generation "midje" :dir "test-project")] + (print (:out result)) + (print (:err result)) + (println "==> Done\n") + (:exit result))) + +;; install leinjacker for the test project to use +(install/install (utils/read-lein-project)) + +(fact "run lein1 tests." + ;; lein1 needs deps resolved to see the installed leinjacker + (runner/run-lein "1" "deps" :dir "test-project") + (run-lein-on-sub-project "1") => 0) + +(fact "run lein2 tests." + (run-lein-on-sub-project "2") => 0) +