Skip to content

Commit

Permalink
introduce check-stdin task
Browse files Browse the repository at this point in the history
This sub-task can be used to check arbitrary list of artifacts provided
via stdin. The check-stdin sub-task will be used as default sub-task if
stdin is available.

The rationale is to reuse version checking machinery of lein-ancient
while allowing more flexible control of input artifacts. Unfortunately
lein-ancient as of 0.6.10 does not evaluate leiningen's project.clj file.
It uses its own way how to read project.clj and interpret it. Probably
due to optional rewriting functionality which needs to understand the
project as data.

Consider this example:

```
(def some-lib-version 1.2.3)
(defproject my-project "X.Y.Z-SNAPSHOT"
  ...
  :dependencies [...
                 [some-company/some-lib ~some-lib-version]
                 ...]
  ...
```

This is a valid leiningen project which evaluates
`some-company/some-lib`dependency as version `1.2.3`. Unfortunately
lein-ancient silently skips such artifact check because it sees
"~some-lib-version" which is not a valid version string. Of course the
code can be arbitrarily complex so it would not be a good solution to
teach lein-ancient to somehow handle this specific case.

With check-stdin task we can use `lein pprint` to extract evaluated
parts of project.clj and pass it into lein-ancient for checking only.

```
lein pprint :dependencies | lein ancient
```

Also note that some future release of lein pprint will support arbitrary
get-in paths[1], so that it will be convenient to extract multiple
lists from different parts of project.clj at once. The check-stdin is
prepared for this and is able to read multiple EDN forms from input and
concatenate them into one list. Also lein pprint supports with-profiles
so it is flexible enough to extract list evaluated in the context of
selected profile(s).

[1] technomancy/leiningen@c63301a
  • Loading branch information
darwin committed Jul 27, 2017
1 parent bbce7ae commit 9c973ce
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 4 deletions.
7 changes: 5 additions & 2 deletions lein-ancient/src/leiningen/ancient.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[upgrade :as u]
[verbose :refer :all]]
[leiningen.core.main :as main]
[jansi-clj.auto]))
[jansi-clj.auto]
[leiningen.ancient.utils :as utils]))


(defn- as-deprecated
Expand All @@ -21,6 +22,7 @@
^:higher-order ^:no-project-needed
^{:subtasks [#'c/check
#'c/check-profiles
#'c/check-stdin
#'g/show-versions
#'g/show-latest
#'u/upgrade
Expand All @@ -33,10 +35,11 @@
(case (first args)
"check" (run c/check)
"check-profiles" (run c/check-profiles)
"check-input" (run c/check-stdin)
"get" (run-deprecated "show-versions" g/show-versions)
"profiles" (run-deprecated "check-profiles" c/check-profiles)
"show-versions" (run g/show-versions)
("show-latest" "latest") (run g/show-latest)
"upgrade" (run u/upgrade)
"upgrade-profiles" (run u/upgrade-profiles)
(apply c/check project args))))
(apply (if (utils/stream-available? System/in) c/check-stdin c/check) project args))))
10 changes: 10 additions & 0 deletions lein-ancient/src/leiningen/ancient/artifact/files.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[zip :as z]]
[leiningen.ancient.verbose :refer :all]
[potemkin :refer [defprotocol+]]
[rewrite-clj.node :as n]
[clojure.java.io :as io]))

;; ## Protocol
Expand Down Expand Up @@ -123,6 +124,15 @@
:zipper-fn z/read-profiles-zipper!
:check-post-fn #(drop-prefixes prefix %))))

(defn virtual-file
"Create new `DependencyFile` value based on a data map"
[path data]
(assert (map? data))
(dependency-file
path
:read-fn (constantly data)
:zipper-fn (constantly (n/map-node data))))

;; ## Example

(comment
Expand Down
17 changes: 17 additions & 0 deletions lein-ancient/src/leiningen/ancient/check.clj
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,20 @@
[opts]
(exit-with-status
(utils/call-on-profiles-files check-file! opts)))

(utils/deftask check-stdin
{:docstring "Check artifacts in list(s) provided via stdin."
:exclude [:interactive :print :no-tests]}
[opts]
(when-not (utils/stream-available? System/in)
(println "please specify artifacts list(s) on stdin.")
(main/exit 1))
(if-some [input (utils/read-edn-forms-from-stream *in*)]
(let [artifacts-list (vec (apply concat input))
fake-project-map {:dependencies artifacts-list}
fake-file (f/virtual-file "<stdin>" fake-project-map)]
(debugf "input artifacts list: %s" artifacts-list)
(exit-with-status
(utils/call-file check-file! opts fake-file)))
(main/exit 2)))

18 changes: 16 additions & 2 deletions lein-ancient/src/leiningen/ancient/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
[collect :as collect]
[verbose :refer :all]]
[jansi-clj.core :as color]
[clojure.string :as string])
(:import [java.io StringWriter PrintWriter]))
[clojure.string :as string]
[clojure.edn :as edn])
(:import [java.io StringWriter PrintWriter InputStream]))

;; ## Reporting

Expand Down Expand Up @@ -165,3 +166,16 @@
(let [~opts opts#]
~@body)))
(cli/doc! ~docstring :exclude ex#))))

(defn stream-available? [^InputStream stream]
(pos? (.available stream)))

(defn read-edn-forms-from-stream [stream]
(try
(let [read-next #(edn/read {:eof ::eof-sentinel} stream)
not-eof? #(not= % ::eof-sentinel)]
(doall (->> (repeatedly read-next)
(take-while not-eof?))))
(catch Throwable e
(errorf "unable to read EDN forms: %s" (str e))
nil)))

0 comments on commit 9c973ce

Please sign in to comment.