forked from clojure/tools.deps.alpha
-
Notifications
You must be signed in to change notification settings - Fork 10
/
specs.clj
182 lines (152 loc) · 6.85 KB
/
specs.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.deps.specs
(:require [clojure.spec.alpha :as s]))
;;;; generic types
(s/def ::lib symbol?)
(s/def ::path string?)
(s/def ::alias keyword?)
;;;; coordinates
;; generic coord attributes
(s/def :deps/root ::path)
(s/def :deps/manifest keyword?)
(s/def :deps/exclusions (s/coll-of ::lib))
(s/def :deps/coord (s/keys :opt [:deps/root :deps/manifest] :opt-un [:deps/exclusions]))
;; maven coords
(s/def :mvn/version string?)
(s/def :mvn/coord (s/merge :deps/coord
(s/keys :req [:mvn/version])))
;; local coords
(s/def :local/root string?)
(s/def :local/coord (s/merge :deps/coord
(s/keys :req [:local/root])))
;; git coords
(s/def :git/url string?)
(s/def :git/sha string?)
(s/def :git/tag string?)
(s/def :git/coord (s/merge :deps/coord
(s/keys :opt [:git/url :git/sha :git/tag])))
;; should this become a multispec?
(s/def ::coord (s/nilable
(s/or :mvn :mvn/coord
:local :local/coord
:git :git/coord)))
(s/def ::path-ref (s/or :path ::path :alias ::alias))
(s/def :aliased/paths (s/coll-of ::path-ref :kind vector? :into []))
;; tool args
;; ::replace-deps - map of lib to coordinate to replace the
(s/def ::tool-args (s/keys :opt-un [::replace-deps ::replace-paths ::deps ::paths]))
(s/def ::replace-deps (s/map-of ::lib ::coord))
(s/def ::replace-paths :aliased/paths)
;; resolve-deps args - used to modify the expanded deps tree
;; ::extra-deps - map of lib to coordinate added to the initial deps collection
;; ::override-deps - map of lib to coordinate to use instead of the coord found during expansion
;; ::default-deps - map of lib to coordinate to use if no coord is specified in extension
(s/def ::resolve-args (s/keys :opt-un [::extra-deps ::override-deps ::default-deps]))
(s/def ::extra-deps (s/map-of ::lib ::coord))
(s/def ::override-deps (s/map-of ::lib ::coord))
(s/def ::default-deps (s/map-of ::lib ::coord))
(s/def ::threads pos-int?)
(s/def ::trace boolean?)
;; make-classpath args - used when constructing the classpath
;; ::classpath-overrides - map of lib to path to use instead of the artifact found during resolution
;; ::extra-paths - collection of extra paths to add to the classpath in addition to ::paths
(s/def ::classpath-args (s/keys :opt-un [::classpath-overrides ::extra-paths]))
(s/def ::classpath-overrides (s/map-of ::lib ::path))
(s/def ::extra-paths :aliased/paths)
;; exec args - used when executing a function with -X or -T
;; ::exec-args - map of default function args
;; ::exec-fn - default function symbol
;; ::ns-default - default namespace to use when resolving functions
;; ::ns-aliases - map of alias to namespace to use when resolving functions
(s/def ::exec-args (s/keys :opt-un [::exec-args ::exec-fn ::ns-default ::ns-aliases]))
(s/def ::exec-args (s/nilable map?))
(s/def ::ns-default simple-symbol?)
(s/def ::ns-aliases (s/map-of simple-symbol? simple-symbol?))
;; deps map (format of the deps.edn file)
(s/def ::paths :aliased/paths)
(s/def ::deps (s/map-of ::lib ::coord))
(s/def ::aliases (s/map-of ::alias any?))
(s/def ::deps-map (s/nilable (s/keys
:opt-un [::paths ::deps ::aliases]
:opt [:mvn/repos :mvn/local-repo :tools/usage :deps/prep-lib])))
;; lib map
;; a map of lib to resolved coordinate (a coord with a ::path) and dependent info
(s/def ::dependents (s/coll-of ::lib))
(s/def ::resolved-coord (s/merge ::coord (s/keys :opt-un [:aliased/paths ::dependents])))
(s/def ::lib-map (s/map-of ::lib ::resolved-coord))
;; classpath
(s/def ::classpath string?)
;; Procurers
;; Maven
(s/def :mvn/repos (s/map-of ::repo-id ::repo))
(s/def ::repo-id string?)
(s/def ::repo (s/nilable (s/keys :opt-un [::url :mvn/releases :mvn/snapshots])))
(s/def ::url string?)
(s/def :mvn-repo/enabled boolean?)
(s/def :mvn-repo/update (s/or :policy #{:daily :always :never} :interval int?))
(s/def :mvn-repo/checksum #{:warn :fail :ignore})
(s/def :mvn/repo-policy (s/keys :opt-un [:mvn-repo/enabled :mvn-repo/update :mvn-repo/checksum]))
(s/def :mvn/releases :mvn/repo-policy)
(s/def :mvn/snapshots :mvn/repo-policy)
(s/def :mvn/local-repo string?)
;; Tool usage
(s/def :tools/usage (s/keys :opt-un [::ns-default ::ns-aliases]))
;; Prep lib
(s/def :deps/prep-lib (s/keys :req-un [:prep/ensure ::alias :prep/fn]))
(s/def :prep/ensure ::path)
(s/def :prep/fn symbol?)
(defn valid-deps?
"Determine whether the deps map is valid according to the specs"
[deps-map]
(s/valid? ::deps-map deps-map))
(defn explain-deps
"If a spec is invalid, return a message explaining why, suitable
for an error message"
[deps-map]
(let [err-data (s/explain-data ::deps-map deps-map)]
(if (nil? err-data)
"Failed spec, reason unknown"
(let [problems (->> (::s/problems err-data)
(sort-by #(- (count (:in %))))
(sort-by #(- (count (:path %)))))
{:keys [path pred val reason via in]} (first problems)]
(str "Found: " (pr-str val) ", expected: " (if reason reason (s/abbrev pred)))))))
;; API
(s/fdef clojure.tools.deps/resolve-deps
:args (s/cat :deps ::deps-map :options ::resolve-args)
:ret ::lib-map)
(s/fdef clojure.tools.deps/make-classpath-map
:args (s/cat :deps ::deps-map, :libs ::lib-map, :classpath-args ::classpath-args)
:ret map?)
(s/fdef clojure.tools.deps/make-classpath
:args (s/cat :libs ::lib-map, :paths ::paths, :classpath-args ::classpath-args)
:ret string?)
(comment
;; some scratch code to recursively check every deps.edn under
;; a root directory whether it's valid against the specs
(require
'[clojure.spec.test.alpha :as stest]
'[clojure.tools.deps :as deps])
(import '[java.nio.file Files Paths FileVisitor FileVisitResult])
(stest/instrument (stest/enumerate-namespace 'clojure.tools.deps))
(Files/walkFileTree
(Paths/get "../" (into-array String []))
(reify FileVisitor
(postVisitDirectory [_ dir ex] FileVisitResult/CONTINUE)
(preVisitDirectory [_ dir attrs] FileVisitResult/CONTINUE)
(visitFileFailed [_ f ex] FileVisitResult/CONTINUE)
(visitFile [_ f attrs]
(when (.endsWith (str f) "/deps.edn")
(print "Checking" (str f))
(let [v (s/valid? ::deps-map (#'deps/slurp-edn-map (.toFile f)))]
(println ":" v)
(when-not v
(s/explain ::deps-map (#'deps/slurp-edn-map (.toFile f))))))
FileVisitResult/CONTINUE)))
)