Permalink
Browse files

Move common functionality to lein-search/util namespace

  • Loading branch information...
1 parent 1f12089 commit 5bc032e081a1cbf6eadb5569e483f6acfba88009 @purcell purcell committed with Licenser Aug 9, 2010
Showing with 178 additions and 152 deletions.
  1. +167 −0 src/lein_search/util.clj
  2. +4 −75 src/leiningen/add.clj
  3. +4 −26 src/leiningen/search.clj
  4. +1 −17 src/leiningen/update.clj
  5. +2 −34 src/leiningen/update_repo.clj
@@ -0,0 +1,167 @@
+(ns lein-search.util
+ (:use [clojure.contrib.duck-streams :only (reader writer with-out-writer)])
+ (:use [clojure.contrib.str-utils :only (chomp str-join)])
+ (:import (java.io File PushbackReader) java.util.zip.GZIPInputStream java.net.URL))
+
+
+(def *lein-dir* (str (System/getProperty "user.home") "/.lein"))
+
+;;; User input functions
+
+(defn good-read-line []
+ (binding [*in* (-> System/in java.io.InputStreamReader.
+ clojure.lang.LineNumberingPushbackReader.)]
+ (read-line)))
+
+(defn prompt-for-input [prompt]
+ (print prompt)
+ (flush)
+ (chomp (good-read-line)))
+
+(defn yes-or-no-prompt [question]
+ (condp = (prompt-for-input (str question " (y/n) "))
+ "y" true
+ "n" false
+ (recur question)))
+
+(defn prompt-for-number [prompt]
+ (try (Integer/parseInt (prompt-for-input prompt))
+ (catch java.lang.NumberFormatException e nil)))
+
+(defn choose-from-numbered-list-if-multiple
+ "Return first item immediately if there is only one, otherwise prompt the user
+with a numbered list of choices."
+ [choices prompt formatter]
+ (if (= 1 (count choices))
+ (first choices)
+ (do (println
+ (str-join "\n"
+ (for [[n i] (map vector (iterate inc 1) choices)]
+ (str n ": " (formatter i)))))
+ (loop []
+ (let [v (prompt-for-number (str prompt ": "))]
+ (if (or (nil? v) (nil? (nth choices (dec v) nil)))
+ (recur)
+ (nth choices (dec v))))))))
+
+;;; Reading/writing clojure forms
+
+(defn read-clj [f]
+ (with-open [r (reader f)]
+ (read (java.io.PushbackReader. r))))
+
+(defn- project-clj-path [project]
+ (str (:root project) "/project.clj"))
+
+(defn read-project-clj [project]
+ (read-clj (project-clj-path project)))
+
+(defn write-project-clj [project forms]
+ (with-out-writer (project-clj-path project)
+ (pr forms)))
+
+
+;;; Modifying defproject forms
+
+;; TODO: this won't add a :dev-dependencies or :dependencies if not already present
+(defn update-dependency-list
+ "Modify the project's dependency list of the given type by passing it through f"
+ [project dep-type f]
+ (->> project
+ (reduce
+ (fn [[form prev] n]
+ (if (= prev dep-type)
+ [(cons (vec (f n)) form) nil]
+ [(cons n form) n]))
+ [() nil])
+ first
+ reverse))
+
+(defn add-artifact [project type artifact version]
+ (update-dependency-list project type
+ (fn [deps]
+ (cons [(symbol artifact) version] deps))))
+
+(defn update-artifact [project dep-type artifact new-version]
+ (update-dependency-list project dep-type
+ (fn [deps]
+ (for [[a v] deps]
+ [a (if (= a (symbol artifact))
+ new-version
+ v)]))))
+
+
+
+;;; Grokking version strings
+
+(defn latest-stable [versions]
+ (first (filter (partial re-find #"^(\d+).(\d+).(\d+)$") versions)))
+
+(defn split-version [v]
+ (if-let [[_ major minor patch suffix] (when v (re-find #"(\d+)\.(\d+)(?:\.(\d+))?(?:-(.*))?" v))]
+ [(Integer/parseInt major) (Integer/parseInt minor) (Integer/parseInt (or patch "0")) (or suffix "")]
+ [0 0 0 ""]))
+
+(defn compare-versions [v1 v2]
+ (let [vers1 (split-version v1)
+ vers2 (split-version v2)
+ version-comparison (.compareTo (subvec vers1 0 3) (subvec vers2 0 3))]
+ (if (zero? version-comparison)
+ (let [v1-suffix (last vers1)
+ v2-suffix (last vers2)]
+ (cond
+ (= v1-suffix v2-suffix) 0
+ (= v1-suffix "") 1
+ (= v2-suffix "") -1
+ (= v1-suffix "SNAPSHOT") 1
+ (= v2-suffix "SNAPSHOT") -1
+ :else (.compareTo v1-suffix v2-suffix)))
+ version-comparison)))
+
+
+;;; Clojars cache
+
+(defn- read-clojars-index [url]
+ (with-open [r (reader (GZIPInputStream. (.openStream (URL. url))))]
+ (let [r (PushbackReader. r)]
+ (loop [result [] code (read r false false)]
+ (if code
+ (recur (conj result code) (read r false false))
+ result)))))
+
+(defn write-clojars-cache []
+ (if (not (.exists (File. *lein-dir*))) (.mkdirs (File. *lein-dir*)))
+ (with-out-writer (str *lein-dir* "/clojars")
+ (pr (read-clojars-index "http://clojars.org/repo/feed.clj.gz"))))
+
+(defn read-clojars-cache []
+ (read-clj (str *lein-dir* "/clojars")))
+
+(defn find-clojar [what]
+ (let [[group artifact] (if-let [match (re-find #"^([^/]+)/(.+)$" what)]
+ (next match)
+ [what what])]
+ (->> (read-clojars-cache)
+ (filter
+ (fn [{artifact-id :artifact-id group-id :group-id}]
+ (and
+ (= artifact-id artifact)
+ (= group-id group)))))))
+
+(defn search-clojar [what]
+ (let [p (re-pattern what)]
+ (doall (filter
+ (fn [{description :description artifact-id :artifact-id group-id :group-id}]
+ (or
+ (re-find p (or description ""))
+ (re-find p artifact-id)
+ (re-find p group-id)))
+ (read-clojars-cache)))))
+
+(defn clojars-artifact-name
+ ([group-id article-id]
+ (if (= group-id article-id)
+ article-id
+ (str group-id "/" article-id)))
+ ([{artifact-id :artifact-id group-id :group-id}]
+ (clojars-artifact-name group-id artifact-id)))
View
@@ -2,77 +2,16 @@
"Interactively adds a dependency from clojars.
With one parameter it will add the latest stable of the corresponding version with two arguments it will take the second argument as version.
If the first parameter is --dev or -d it will work exactly as without --dev just that it will add a dev dependency."
- (:use (clojure.contrib duck-streams seq-utils str-utils)
- [leiningen.update-repo :only [*lein-dir*]]
- [leiningen.search :only [read-clj search-clojar artifact-name]]))
+ (:use [clojure.contrib.str-utils :only (str-join)]
+ lein-search.util))
-(defn good-read-line []
- (binding [*in* (-> System/in (java.io.InputStreamReader.) (clojure.lang.LineNumberingPushbackReader.))] (read-line)))
-
-(defn prompt-for-input [prompt]
- (print prompt)
- (flush)
- (chomp (good-read-line)))
-
-(defn prompt-for-number [prompt]
- (try (Integer/parseInt (prompt-for-input prompt))
- (catch java.lang.NumberFormatException e nil)))
-
-(defn update-dependency-list
- "Modify the project's dependency list of the given type by passing it through f"
- [project dep-type f]
- (->> project
- (reduce
- (fn [[form prev] n]
- (if (= prev dep-type)
- [(cons (vec (f n)) form) nil]
- [(cons n form) n]))
- [() nil])
- first
- reverse))
-
-(defn add-artifact [project type artifact version]
- (update-dependency-list project type
- (fn [deps]
- (cons [(symbol artifact) version] deps))))
-
-(defn find-clojar [what]
- (let [[group artifact] (if-let [match (re-find #"^([^/]+)/(.+)$" what)]
- (next match)
- [what what])]
- (->> (read-clj (str *lein-dir* "/clojars"))
- (filter
- (fn [{artifact-id :artifact-id group-id :group-id}]
- (and
- (= artifact-id artifact)
- (= group-id group)))))))
-
-(defn choose-from-numbered-list-if-multiple
- "Return first item immediately if there is only one, otherwise prompt the user
-with a numbered list of choices."
- [choices prompt formatter]
- (if (= 1 (count choices))
- (first choices)
- (do (println
- (str-join "\n"
- (for [[n i] (map vector (iterate inc 1) choices)]
- (str n ": " (formatter i)))))
- (loop []
- (let [v (prompt-for-number (str prompt ": "))]
- (if (or (nil? v) (nil? (nth choices (dec v) nil)))
- (recur)
- (nth choices (dec v))))))))
-
(defn get-version [[artifact-name available-versions]]
[artifact-name
(choose-from-numbered-list-if-multiple available-versions
"Please select a version"
(fn [v] (str artifact-name " " v)))])
-(defn latest-stable [versions]
- (first (filter (partial re-find #"^(\d+).(\d+).(\d+)$") versions)))
-
(defn get-artifact-id [res]
(get-version
(choose-from-numbered-list-if-multiple res
@@ -81,16 +20,6 @@ with a numbered list of choices."
(str name " (" (str-join ", " vers) ")")))))
(defn add [project artifact & args]
-(defn- project-clj-path [project]
- (str (:root project) "/project.clj"))
-
-(defn read-project-clj [project]
- (read-clj (project-clj-path project)))
-
-(defn write-project-clj [project forms]
- (with-out-writer (project-clj-path project)
- (pr forms)))
-
(let [dev (or (= artifact "--dev") (= artifact "-d"))
artifact (if dev (first args) artifact)
args (if dev (rest args) args)
@@ -100,8 +29,8 @@ with a numbered list of choices."
(if (empty? res)
(println "Sorry; nothing on clojars that matches" artifact (if version ""))
(if (and version (not-any? (partial = version) (:versions res)))
- (println "Sorry; there is no version" version "for" (artifact-name res) ". Try one of:" (str-join ", " (:versions res)))
- (let [[a v] [(artifact-name res) (if version version (latest-stable (:versions res)))]]
+ (println "Sorry; there is no version" version "for" (clojars-artifact-name res) ". Try one of:" (str-join ", " (:versions res)))
+ (let [[a v] [(clojars-artifact-name res) (if version version (latest-stable (:versions res)))]]
(println "Adding:" a v)
(write-project-clj project
(add-artifact (read-project-clj project)
@@ -1,39 +1,17 @@
(ns leiningen.search
"Searches the indexed clojars.org repository. Giving -v as first argument prints the versions instead of the description."
- (:use (clojure.contrib duck-streams seq-utils str-utils)
- [leiningen.update-repo :only [*lein-dir* compare-versions]])
+ (:use [clojure.contrib.str-utils :only (str-join re-sub)]
+ lein-search.util)
(:import java.io.File))
-(defn read-clj [f]
- (with-open [r (reader f)]
- (read (java.io.PushbackReader. r))))
-
-(defn search-clojar [what]
- (let [p (re-pattern what)]
- (doall (filter
- (fn [{description :description artifact-id :artifact-id group-id :group-id}]
- (or
- (re-find p (or description ""))
- (re-find p artifact-id)
- (re-find p group-id)))
- (read-clj (str *lein-dir* "/clojars"))))))
-
-(defn artifact-name
- ([group-id article-id]
- (if (= group-id article-id)
- article-id
- (str group-id "/" article-id)))
- ([{artifact-id :artifact-id group-id :group-id}]
- (artifact-name group-id artifact-id)))
-
(defn search [project what & args]
(let [show-versions (= "-v" what)
what (if show-versions (first args) what)]
(if (.exists (File. (str *lein-dir* "/clojars")))
(let [m (search-clojar what)]
(println "Results for " what ":")
(if show-versions
- (println (str-join "\n" (map (fn [{versions :versions artifact-id :artifact-id group-id :group-id}] (str (artifact-name group-id artifact-id) ": " (str-join ", " versions))) m)))
- (println (str-join "\n" (map (fn [{description :description artifact-id :artifact-id group-id :group-id}] (format "%-40s - %s" (artifact-name group-id artifact-id) (re-sub #"\n\s*" " " (or description "No description given")))) m)))))
+ (println (str-join "\n" (map (fn [{versions :versions artifact-id :artifact-id group-id :group-id}] (str (clojars-artifact-name group-id artifact-id) ": " (str-join ", " versions))) m)))
+ (println (str-join "\n" (map (fn [{description :description artifact-id :artifact-id group-id :group-id}] (format "%-40s - %s" (clojars-artifact-name group-id artifact-id) (re-sub #"\n\s*" " " (or description "No description given")))) m)))))
(println "No repo index found, please run lein update first."))))
@@ -1,24 +1,8 @@
(ns leiningen.update
"lein update checks for newer versions of currently used dependencies and aks the user if they should be updated to the latest stable."
- (:use (clojure.contrib duck-streams seq-utils str-utils)
- [leiningen.add :only [latest-stable add-artifact find-clojar good-read-line update-dependency-list prompt-for-input read-project-clj write-project-clj]]
- [leiningen.update-repo :only [compare-versions]]))
+ (:use lein-search.util))
-(defn update-artifact [project dep-type artifact new-version]
- (update-dependency-list project dep-type
- (fn [deps]
- (for [[a v] deps]
- [a (if (= a (symbol artifact))
- new-version
- v)]))))
-
-(defn yes-or-no-prompt [question]
- (condp = (prompt-for-input (str question " (y/n) "))
- "y" true
- "n" false
- (recur question)))
-
(defn ask-for-update [artifact version new-version]
(yes-or-no-prompt (str "You are currently using "artifact" version "version". Do you want to update to "new-version"?")))
@@ -1,40 +1,8 @@
(ns leiningen.update-repo
"Updates the clojars.org repositories index."
- (:use [clojure.contrib.duck-streams :only (reader writer with-out-writer)])
- (:import (java.io File) java.util.zip.GZIPInputStream java.net.URL))
+ (:use lein-search.util))
-(def *lein-dir* (str (System/getProperty "user.home") "/.lein"))
-
-(defn split-version [v]
- (if-let [[_ major minor patch suffix] (when v (re-find #"(\d+)\.(\d+)(?:\.(\d+))?(?:-(.*))?" v))]
- [(Integer/parseInt major) (Integer/parseInt minor) (Integer/parseInt (or patch "0")) (or suffix "")]
- [0 0 0 ""]))
-
-(defn compare-versions [v1 v2]
- (let [vers1 (split-version v1)
- vers2 (split-version v2)
- version-comparison (.compareTo (subvec vers1 0 3) (subvec vers2 0 3))]
- (if (zero? version-comparison)
- (let [v1-suffix (last vers1)
- v2-suffix (last vers2)]
- (cond
- (= v1-suffix v2-suffix) 0
- (= v1-suffix "") 1
- (= v2-suffix "") -1
- (= v1-suffix "SNAPSHOT") 1
- (= v2-suffix "SNAPSHOT") -1
- :else (.compareTo v1-suffix v2-suffix)))
- version-comparison)))
-
-(defn read-index [url]
- (with-open [r (reader (GZIPInputStream. (.openStream (URL. url))))]
- (loop [result [] code (read r false false)]
- (if code
- (recur (conj result code) (read r false false))
- result))))
(defn update-repo [project & args]
- (if (not (.exists (File. *lein-dir*))) (.mkdirs (File. *lein-dir*)))
(println "Getting the list of packages on clojars.org ...")
- (with-out-writer (str *lein-dir* "/clojars")
- (pr (read-index "http://clojars.org/repo/feed.clj.gz"))))
+ (write-clojars-cache))

0 comments on commit 5bc032e

Please sign in to comment.