forked from Licenser/lein-search
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move common functionality to lein-search/util namespace
- Loading branch information
Showing
5 changed files
with
178 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.")))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) |