├── VERSION_TEMPLATE
├── CHANGELOG.md
├── .gitignore
├── .github
├── workflows
│ ├── snapshot.yml
│ ├── doc-build.yml
│ ├── release.yml
│ └── test.yml
└── PULL_REQUEST_TEMPLATE
├── script
└── version
├── CONTRIBUTING.md
├── src
├── test
│ └── clojure
│ │ └── clojure
│ │ └── tools
│ │ └── deps
│ │ ├── util.clj
│ │ └── test_edn.clj
└── main
│ └── clojure
│ └── clojure
│ └── tools
│ └── deps
│ ├── specs.clj
│ └── edn.clj
├── README.md
├── pom.xml
└── LICENSE
/VERSION_TEMPLATE:
--------------------------------------------------------------------------------
1 | 0.1.GENERATED_VERSION
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | ===========
3 |
4 | * next
5 | *
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea/
3 | .calva/
4 | .lsp/
5 | target/
6 | .nrepl*
7 | .cpcache
8 | .lein*
9 | project.clj
10 | .clj-kondo/.cache
11 | test-out/
12 | .vscode/
13 | .clj-watson/
14 |
--------------------------------------------------------------------------------
/.github/workflows/snapshot.yml:
--------------------------------------------------------------------------------
1 | name: Snapshot on demand
2 |
3 | on: [workflow_dispatch]
4 |
5 | jobs:
6 | call-snapshot:
7 | uses: clojure/build.ci/.github/workflows/snapshot.yml@master
8 | secrets: inherit
9 |
--------------------------------------------------------------------------------
/.github/workflows/doc-build.yml:
--------------------------------------------------------------------------------
1 | name: Build API Docs
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | call-doc-build-workflow:
8 | uses: clojure/build.ci/.github/workflows/doc-build.yml@master
9 | with:
10 | project: clojure/tools.deps.edn
11 |
--------------------------------------------------------------------------------
/script/version:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | version_template=`cat VERSION_TEMPLATE`
6 | commit_count=`git rev-list HEAD --count`
7 |
8 | if [[ "$version_template" =~ ^[0-9]+\.[0-9]+\.GENERATED_VERSION(-[a-zA-Z0-9]+)?$ ]]; then
9 |
10 | echo ${version_template/GENERATED_VERSION/$commit_count}
11 |
12 | else
13 | echo "Invalid version template string: $version_template" >&2
14 | exit -1
15 | fi
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | This is a [Clojure contrib] project.
2 |
3 | Under the Clojure contrib [guidelines], this project cannot accept
4 | pull requests. All patches must be submitted via [JIRA].
5 |
6 | See [Contributing] on the Clojure website for
7 | more information on how to contribute.
8 |
9 | [Clojure contrib]: https://clojure.org/community/contrib_libs
10 | [Contributing]: https://clojure.org/community/contributing
11 | [JIRA]: https://clojure.atlassian.net/browse/TDEPS
12 | [guidelines]: https://clojure.org/community/contrib_howto
13 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release on demand
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | releaseVersion:
7 | description: "Version to release"
8 | required: true
9 | snapshotVersion:
10 | description: "Snapshot version after release"
11 | required: true
12 |
13 | jobs:
14 | call-release:
15 | uses: clojure/build.ci/.github/workflows/release.yml@master
16 | with:
17 | releaseVersion: ${{ github.event.inputs.releaseVersion }}
18 | snapshotVersion: ${{ github.event.inputs.snapshotVersion }}
19 | secrets: inherit
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | test:
7 | strategy:
8 | matrix:
9 | os: [ubuntu-latest] # macOS-latest, windows-latest]
10 | java-version: ["8", "11", "17", "21"]
11 | clojure-version: ["1.10.3", "1.11.1"]
12 | runs-on: ${{ matrix.os }}
13 | steps:
14 | - uses: actions/checkout@v4
15 | - name: Set up Java
16 | uses: actions/setup-java@v4
17 | with:
18 | java-version: ${{ matrix.java-version }}
19 | distribution: 'temurin'
20 | cache: 'maven'
21 | - name: Build with Maven
22 | run: mvn -ntp -B -Dclojure.version=${{ matrix.clojure-version }} clean test
23 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE:
--------------------------------------------------------------------------------
1 | Hi! Thanks for your interest in contributing to this project.
2 |
3 | Clojure contrib projects do not use GitHub issues or pull requests, and
4 | require a signed Contributor Agreement. If you would like to contribute,
5 | please read more about the CA and sign that first (this can be done online).
6 |
7 | Then go to this project's issue tracker in JIRA to create tickets, update
8 | tickets, or submit patches. For help in creating tickets and patches,
9 | please see:
10 |
11 | - Contributing FAQ: https://clojure.org/dev
12 | - Signing the CA: https://clojure.org/dev/contributor_agreement
13 | - Creating Tickets: https://clojure.org/dev/creating_tickets
14 | - Developing Patches: https://clojure.org/dev/developing_patches
15 |
--------------------------------------------------------------------------------
/src/test/clojure/clojure/tools/deps/util.clj:
--------------------------------------------------------------------------------
1 | (ns clojure.tools.deps.util)
2 |
3 | (defn submap?
4 | "Is m1 a subset of m2?"
5 | [m1 m2]
6 | (if (and (map? m1) (map? m2))
7 | (every? (fn [[k v]] (and (contains? m2 k)
8 | (submap? v (get m2 k))))
9 | m1)
10 | (= m1 m2)))
11 |
12 | (defn submap-debug?
13 | "Is m1 a subset of m2?
14 | Print missing keys or mismatched values."
15 | [m1 m2]
16 | (if (and (map? m1) (map? m2))
17 | (every? (fn [[k v]]
18 | (when (not (contains? m2 k)) (println "m1 has key, m2 does not: " k))
19 | (and (contains? m2 k) (submap? v (get m2 k))))
20 | m1)
21 | (if (= m1 m2)
22 | true
23 | (do
24 | (println "Nested values don't match, m1 val=" m1 "m2 val=" m2)
25 | false))))
26 |
--------------------------------------------------------------------------------
/src/test/clojure/clojure/tools/deps/test_edn.clj:
--------------------------------------------------------------------------------
1 | (ns clojure.tools.deps.test-edn
2 | (:require
3 | [clojure.test :refer [deftest is are testing]]
4 | [clojure.tools.deps.edn :as deps-edn])
5 | (:import
6 | [java.io File]))
7 |
8 | (deftest test-slurp-deps-on-nonexistent-file
9 | (is (nil? (deps-edn/read-deps (File. "NONEXISTENT_FILE")))))
10 |
11 | (deftest test-merge-or-replace
12 | (are [vals ret]
13 | (= ret (apply #'deps-edn/merge-or-replace vals))
14 |
15 | [nil nil] nil
16 | [nil {:a 1}] {:a 1}
17 | [{:a 1} nil] {:a 1}
18 | [{:a 1 :b 1} {:a 2 :c 3} {:c 4 :d 5}] {:a 2 :b 1 :c 4 :d 5}
19 | [nil 1] 1
20 | [1 nil] 1
21 | [1 2] 2))
22 |
23 | (deftest test-merge-edns
24 | (is (= (deps-edn/merge-edns
25 | [{:deps {'a {:v 1}, 'b {:v 1}}
26 | :a/x {:a 1}
27 | :a/y "abc"}
28 | {:deps {'b {:v 2}, 'c {:v 3}}
29 | :a/x {:b 1}
30 | :a/y "def"}
31 | nil])
32 | {:deps {'a {:v 1}, 'b {:v 2}, 'c {:v 3}}
33 | :a/x {:a 1, :b 1}
34 | :a/y "def"})))
35 |
36 | (deftest merge-alias-maps
37 | (are [m1 m2 out]
38 | (= out (#'deps-edn/merge-alias-maps m1 m2))
39 |
40 | {} {} {}
41 | {} {:extra-deps {:a 1}} {:extra-deps {:a 1}}
42 | {:extra-deps {:a 1 :b 1}} {:extra-deps {:b 2}} {:extra-deps {:a 1 :b 2}}
43 | {} {:default-deps {:a 1}} {:default-deps {:a 1}}
44 | {:default-deps {:a 1 :b 1}} {:default-deps {:b 2}} {:default-deps {:a 1 :b 2}}
45 | {} {:override-deps {:a 1}} {:override-deps {:a 1}}
46 | {:override-deps {:a 1 :b 1}} {:override-deps {:b 2}} {:override-deps {:a 1 :b 2}}
47 | {} {:extra-paths ["a" "b"]} {:extra-paths ["a" "b"]}
48 | {:extra-paths ["a" "b"]} {:extra-paths ["c" "d"]} {:extra-paths ["a" "b" "c" "d"]}
49 | {} {:jvm-opts ["-Xms100m" "-Xmx200m"]} {:jvm-opts ["-Xms100m" "-Xmx200m"]}
50 | {:jvm-opts ["-Xms100m" "-Xmx200m"]} {:jvm-opts ["-Dfoo=bar"]} {:jvm-opts ["-Xms100m" "-Xmx200m" "-Dfoo=bar"]}
51 | {} {:main-opts ["foo.bar" "1"]} {:main-opts ["foo.bar" "1"]}
52 | {:main-opts ["foo.bar" "1"]} {:main-opts ["foo.baz" "2"]} {:main-opts ["foo.baz" "2"]}))
53 |
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | tools.deps.edn
2 | ========================================
3 |
4 | Reader for deps.edn
5 |
6 | # Rationale
7 |
8 | This library is a small library for reading and understanding deps.edn files. It can
9 | be used in scenarios where the full [tools.deps](https://github.com/clojure/tools.deps)
10 | library is not needed.
11 |
12 | * [deps.edn Reference](https://clojure.org/reference/deps_edn)
13 |
14 | # Release Information
15 |
16 | Latest release: TBD
17 |
18 | * [All released versions](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22tools.deps.edn%22)
19 |
20 | [deps.edn](https://clojure.org/reference/deps_edn) dependency information:
21 |
22 | ```
23 | org.clojure/tools.deps.edn {:mvn/version "TBD"}
24 | ```
25 |
26 | [Leiningen](https://github.com/technomancy/leiningen/) dependency information:
27 |
28 | ```
29 | [org.clojure/tools.deps.edn "TBD"]
30 | ```
31 |
32 | [Maven](https://maven.apache.org) dependency information:
33 |
34 | ```
35 |
36 | org.clojure
37 | tools.deps.edn
38 | TBD
39 |
40 | ```
41 |
42 | # API
43 |
44 | For info on using tools.deps.edn as a library, see:
45 |
46 | * [API Docs](https://clojure.github.io/tools.deps.edn)
47 |
48 | # Developer Information
49 |
50 | * [GitHub project](https://github.com/clojure/tools.deps.edn)
51 | * [How to contribute](https://clojure.org/community/contributing)
52 | * [Bug Tracker](https://clojure.atlassian.net/browse/TDEPS)
53 | * [Continuous Integration](https://github.com/clojure/tools.deps.edn/actions/workflows/test.yml)
54 |
55 | # Copyright and License
56 |
57 | Copyright © Rich Hickey, Alex Miller, and contributors
58 |
59 | All rights reserved. The use and
60 | distribution terms for this software are covered by the
61 | [Eclipse Public License 1.0] which can be found in the file
62 | LICENSE at the root of this distribution. By using this software
63 | in any fashion, you are agreeing to be bound by the terms of this
64 | license. You must not remove this notice, or any other, from this
65 | software.
66 |
67 | [Eclipse Public License 1.0]: https://opensource.org/license/epl-1-0/
68 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | tools.deps.edn
4 | 0.1.0-SNAPSHOT
5 | tools.deps.edn
6 |
7 |
8 | org.clojure
9 | pom.contrib
10 | 1.3.0
11 |
12 |
13 |
14 |
15 | puredanger
16 | Alex Miller
17 |
18 |
19 |
20 |
21 |
22 | true
23 | 1.12.0
24 |
25 |
26 |
27 |
28 | org.clojure
29 | clojure
30 | ${clojure.version}
31 |
32 |
33 |
34 |
35 |
36 |
37 | src/main/resources
38 | true
39 |
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-resources-plugin
45 | 3.1.0
46 |
47 |
48 |
51 | com.theoryinpractise
52 | clojure-maven-plugin
53 | 1.7.1
54 | true
55 |
56 | ${clojure.warnOnReflection}
57 | true
58 |
59 |
60 |
61 | clojure-compile
62 | none
63 |
64 |
65 | clojure-test
66 | test
67 |
68 | test
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | scm:git:git@github.com:clojure/tools.deps.edn.git
78 | scm:git:git@github.com:clojure/tools.deps.edn.git
79 | git@github.com:clojure/tools.deps.edn.git
80 | HEAD
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/deps/specs.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.deps.specs
10 | (:require [clojure.spec.alpha :as s]))
11 |
12 | ;;;; generic types
13 |
14 | (s/def ::lib symbol?)
15 | (s/def ::path string?)
16 | (s/def ::alias keyword?)
17 |
18 | ;;;; coordinates
19 |
20 | ;; generic coord attributes
21 | (s/def :deps/root ::path)
22 | (s/def :deps/manifest keyword?)
23 | (s/def :deps/exclusions (s/coll-of ::lib))
24 | (s/def :deps/coord (s/keys :opt [:deps/root :deps/manifest] :opt-un [:deps/exclusions]))
25 |
26 | ;; maven coords
27 | (s/def :mvn/version string?)
28 | (s/def :mvn/coord (s/merge :deps/coord
29 | (s/keys :req [:mvn/version])))
30 |
31 | ;; local coords
32 | (s/def :local/root string?)
33 | (s/def :local/coord (s/merge :deps/coord
34 | (s/keys :req [:local/root])))
35 |
36 | ;; git coords
37 | (s/def :git/url string?)
38 | (s/def :git/sha string?)
39 | (s/def :git/tag string?)
40 | (s/def :git/coord (s/merge :deps/coord
41 | (s/keys :opt [:git/url :git/sha :git/tag])))
42 |
43 | ;; should this become a multispec?
44 | (s/def ::coord (s/nilable
45 | (s/or :mvn :mvn/coord
46 | :local :local/coord
47 | :git :git/coord)))
48 |
49 | (s/def ::path-ref (s/or :path ::path :alias ::alias))
50 | (s/def :aliased/paths (s/coll-of ::path-ref :kind vector? :into []))
51 |
52 | ;; tool args
53 | ;; ::replace-deps - map of lib to coordinate to replace the
54 | (s/def ::tool-args (s/keys :opt-un [::replace-deps ::replace-paths ::deps ::paths]))
55 | (s/def ::replace-deps (s/map-of ::lib ::coord))
56 | (s/def ::replace-paths :aliased/paths)
57 |
58 | ;; resolve-deps args - used to modify the expanded deps tree
59 | ;; ::extra-deps - map of lib to coordinate added to the initial deps collection
60 | ;; ::override-deps - map of lib to coordinate to use instead of the coord found during expansion
61 | ;; ::default-deps - map of lib to coordinate to use if no coord is specified in extension
62 | (s/def ::resolve-args (s/keys :opt-un [::extra-deps ::override-deps ::default-deps]))
63 | (s/def ::extra-deps (s/map-of ::lib ::coord))
64 | (s/def ::override-deps (s/map-of ::lib ::coord))
65 | (s/def ::default-deps (s/map-of ::lib ::coord))
66 | (s/def ::threads pos-int?)
67 | (s/def ::trace boolean?)
68 |
69 | ;; make-classpath args - used when constructing the classpath
70 | ;; ::classpath-overrides - map of lib to path to use instead of the artifact found during resolution
71 | ;; ::extra-paths - collection of extra paths to add to the classpath in addition to ::paths
72 | (s/def ::classpath-args (s/keys :opt-un [::classpath-overrides ::extra-paths]))
73 | (s/def ::classpath-overrides (s/map-of ::lib ::path))
74 | (s/def ::extra-paths :aliased/paths)
75 |
76 | ;; exec args - used when executing a function with -X or -T
77 | ;; ::exec-args - map of default function args
78 | ;; ::exec-fn - default function symbol
79 | ;; ::ns-default - default namespace to use when resolving functions
80 | ;; ::ns-aliases - map of alias to namespace to use when resolving functions
81 | (s/def ::exec-args (s/keys :opt-un [::exec-args ::exec-fn ::ns-default ::ns-aliases]))
82 | (s/def ::exec-args (s/nilable map?))
83 | (s/def ::ns-default simple-symbol?)
84 | (s/def ::ns-aliases (s/map-of simple-symbol? simple-symbol?))
85 |
86 | ;; deps map (format of the deps.edn file)
87 | (s/def ::paths :aliased/paths)
88 | (s/def ::deps (s/map-of ::lib ::coord))
89 | (s/def ::aliases (s/map-of ::alias any?))
90 | (s/def ::deps-map (s/nilable (s/keys
91 | :opt-un [::paths ::deps ::aliases]
92 | :opt [:mvn/repos :mvn/local-repo :tools/usage :deps/prep-lib])))
93 |
94 | ;; lib map
95 | ;; a map of lib to resolved coordinate (a coord with a ::path) and dependent info
96 | (s/def ::dependents (s/coll-of ::lib))
97 | (s/def ::resolved-coord (s/merge ::coord (s/keys :opt-un [:aliased/paths ::dependents])))
98 | (s/def ::lib-map (s/map-of ::lib ::resolved-coord))
99 |
100 | ;; classpath
101 | (s/def ::classpath string?)
102 |
103 | ;; Procurers
104 |
105 | ;; Maven
106 | (s/def :mvn/repos (s/map-of ::repo-id ::repo))
107 | (s/def ::repo-id string?)
108 | (s/def ::repo (s/nilable (s/keys :opt-un [::url :mvn/releases :mvn/snapshots])))
109 | (s/def ::url string?)
110 | (s/def :mvn-repo/enabled boolean?)
111 | (s/def :mvn-repo/update (s/or :policy #{:daily :always :never} :interval int?))
112 | (s/def :mvn-repo/checksum #{:warn :fail :ignore})
113 | (s/def :mvn/repo-policy (s/keys :opt-un [:mvn-repo/enabled :mvn-repo/update :mvn-repo/checksum]))
114 | (s/def :mvn/releases :mvn/repo-policy)
115 | (s/def :mvn/snapshots :mvn/repo-policy)
116 | (s/def :mvn/local-repo string?)
117 |
118 | ;; Tool usage
119 | (s/def :tools/usage (s/keys :opt-un [::ns-default ::ns-aliases]))
120 |
121 | ;; Prep lib
122 | (s/def :deps/prep-lib (s/keys :req-un [:prep/ensure ::alias :prep/fn]))
123 | (s/def :prep/ensure ::path)
124 | (s/def :prep/fn symbol?)
125 |
126 | (defn valid-deps?
127 | "Determine whether the deps map is valid according to the specs"
128 | [deps-map]
129 | (s/valid? ::deps-map deps-map))
130 |
131 | (defn explain-deps
132 | "If a spec is invalid, return a message explaining why, suitable
133 | for an error message"
134 | [deps-map]
135 | (let [err-data (s/explain-data ::deps-map deps-map)]
136 | (if (nil? err-data)
137 | "Failed spec, reason unknown"
138 | (let [problems (->> (::s/problems err-data)
139 | (sort-by #(- (count (:in %))))
140 | (sort-by #(- (count (:path %)))))
141 | {:keys [path pred val reason via in]} (first problems)]
142 | (str "Found: " (pr-str val) ", expected: " (if reason reason (s/abbrev pred)))))))
143 |
144 | (comment
145 | ;; some scratch code to recursively check every deps.edn under
146 | ;; a root directory whether it's valid against the specs
147 | (require
148 | '[clojure.spec.test.alpha :as stest]
149 | '[clojure.tools.deps :as deps])
150 | (import '[java.nio.file Files Paths FileVisitor FileVisitResult])
151 | (stest/instrument (stest/enumerate-namespace 'clojure.tools.deps))
152 |
153 | (Files/walkFileTree
154 | (Paths/get "../" (into-array String []))
155 | (reify FileVisitor
156 | (postVisitDirectory [_ dir ex] FileVisitResult/CONTINUE)
157 | (preVisitDirectory [_ dir attrs] FileVisitResult/CONTINUE)
158 | (visitFileFailed [_ f ex] FileVisitResult/CONTINUE)
159 | (visitFile [_ f attrs]
160 | (when (.endsWith (str f) "/deps.edn")
161 | (print "Checking" (str f))
162 | (let [v (s/valid? ::deps-map (#'deps/slurp-edn-map (.toFile f)))]
163 | (println ":" v)
164 | (when-not v
165 | (s/explain ::deps-map (#'deps/slurp-edn-map (.toFile f))))))
166 | FileVisitResult/CONTINUE)))
167 | )
168 |
--------------------------------------------------------------------------------
/src/main/clojure/clojure/tools/deps/edn.clj:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | (ns clojure.tools.deps.edn
10 | (:require
11 | [clojure.edn :as edn]
12 | [clojure.java.io :as jio]
13 | [clojure.string :as str]
14 | [clojure.tools.deps.specs :as specs]
15 | [clojure.walk :as walk])
16 | (:import
17 | [java.io File PushbackReader]
18 | [clojure.lang EdnReader$ReaderException]
19 | ))
20 |
21 | (set! *warn-on-reflection* true)
22 |
23 | ;;;; Read
24 |
25 | (defonce ^:private nl (System/getProperty "line.separator"))
26 |
27 | (defn- printerrln
28 | "println to *err*"
29 | [& msgs]
30 | (binding [*out* *err*
31 | *print-readably* nil]
32 | (pr (str (str/join " " msgs) nl))
33 | (flush)))
34 |
35 | (defn- io-err
36 | "Helper function to construct an ex-info for an exception reading
37 | file at path with the message format fmt (which should have one
38 | variable for the path)."
39 | ^Throwable [fmt & {:keys [path]}]
40 | (let [abs-path (.getAbsolutePath (jio/file path))]
41 | (ex-info (format fmt abs-path) {:path abs-path})))
42 |
43 | (defn read-edn
44 | "Read edn from file f, which should contain exactly one edn value.
45 | If f exists but is blank, nil is returned.
46 | Throws if file is unreadable or contains multiple values.
47 | Opts:
48 | :path String path to file being read"
49 | [^File f & opts]
50 | (with-open [rdr (PushbackReader. (jio/reader f))]
51 | (let [EOF (Object.)
52 | val (try
53 | (let [val (edn/read {:default tagged-literal :eof EOF} rdr)]
54 | (if (identical? EOF val)
55 | nil ;; empty file
56 | (if (not (identical? EOF (edn/read {:eof EOF} rdr)))
57 | (throw (ex-info "Expected edn to contain a single value." {}))
58 | val)))
59 | (catch EdnReader$ReaderException e
60 | (throw (io-err (str (.getMessage e) " (%s)") opts)))
61 | (catch RuntimeException t
62 | (if (str/starts-with? (.getMessage t) "EOF while reading")
63 | (throw (io-err "Error reading edn, delimiter unmatched (%s)" opts))
64 | (throw (io-err (str "Error reading edn. " (.getMessage t) " (%s)") opts)))))])))
65 |
66 | (defn validate
67 | "Validate a deps-edn map according to the specs, throw if invalid.
68 | Opts:
69 | :path String path to file being read"
70 | [deps-edn & opts]
71 | (if (specs/valid-deps? deps-edn)
72 | deps-edn
73 | (throw (io-err (str "Error reading deps %s. " (specs/explain-deps deps-edn)) opts))))
74 |
75 | ;;;; Canonicalize
76 |
77 | (defn- canonicalize-sym
78 | [s & opts]
79 | (if (simple-symbol? s)
80 | (let [cs (as-> (name s) n (symbol n n))]
81 | (printerrln "DEPRECATED: Libs must be qualified, change" s "=>" cs
82 | (if-let [path (:path opts)] (str "(" path ")" "")))
83 | cs)
84 | s))
85 |
86 | (defn- canonicalize-exclusions
87 | [{:keys [exclusions] :as coord} & opts]
88 | (if (seq (filter simple-symbol? exclusions))
89 | (assoc coord :exclusions (mapv #(canonicalize-sym % opts) exclusions))
90 | coord))
91 |
92 | (defn- canonicalize-dep-map
93 | [deps-map & opts]
94 | (when deps-map
95 | (reduce-kv (fn [acc lib coord]
96 | (let [new-lib (if (simple-symbol? lib) (canonicalize-sym lib opts) lib)
97 | new-coord (canonicalize-exclusions coord opts)]
98 | (assoc acc new-lib new-coord)))
99 | {} deps-map)))
100 |
101 | (defn canonicalize
102 | "Canonicalize a deps.edn map (convert simple lib symbols to qualified lib symbols).
103 | Opts:
104 | :path String path to file being read"
105 | [deps-edn & opts]
106 | (walk/postwalk
107 | (fn [x]
108 | (if (map? x)
109 | (reduce (fn [xr k]
110 | (if-let [xm (get xr k)]
111 | (assoc xr k (canonicalize-dep-map xm opts))
112 | xr))
113 | x #{:deps :default-deps :override-deps :extra-deps :classpath-overrides})
114 | x))
115 | deps-edn))
116 |
117 | ;;;; Read deps with validation and canonicalization
118 |
119 | (defn read-deps
120 | "Corece f to a file with jio/file, then read, validate, and canonicalize
121 | the deps.edn. This is the primary entry point for reading.
122 |
123 | Opts: none"
124 | [f & opts]
125 | (let [file (jio/file f)
126 | opts {:path (.getPath file)}]
127 | (when (.exists file)
128 | (-> file (read-edn opts) (validate opts) (canonicalize opts)))))
129 |
130 | ;;;; deps edn manipulation
131 |
132 | (defn- merge-or-replace
133 | "If maps, merge, otherwise replace"
134 | [& vals]
135 | (when (some identity vals)
136 | (reduce (fn [ret val]
137 | (if (and (map? ret) (map? val))
138 | (merge ret val)
139 | (or val ret)))
140 | nil vals)))
141 |
142 | (defn merge-edns
143 | "Merge multiple deps edn maps from left to right into a single deps edn map."
144 | [deps-edn-maps]
145 | (apply merge-with merge-or-replace (remove nil? deps-edn-maps)))
146 |
147 | ;;;; Aliases
148 |
149 | ;; per-key binary merge-with rules
150 |
151 | (def ^:private last-wins (comp last #(remove nil? %) vector))
152 | (def ^:private append (comp vec concat))
153 | (def ^:private append-unique (comp vec distinct concat))
154 |
155 | (def ^:private merge-alias-rules
156 | {:deps merge ;; FUTURE: remove
157 | :replace-deps merge ;; formerly :deps
158 | :extra-deps merge
159 | :override-deps merge
160 | :default-deps merge
161 | :classpath-overrides merge
162 | :paths append-unique ;; FUTURE: remove
163 | :replace-paths append-unique ;; formerly :paths
164 | :extra-paths append-unique
165 | :jvm-opts append
166 | :main-opts last-wins
167 | :exec-fn last-wins
168 | :exec-args merge-or-replace
169 | :ns-aliases merge
170 | :ns-default last-wins})
171 |
172 | (defn- choose-rule [alias-key val]
173 | (or (merge-alias-rules alias-key)
174 | (if (map? val)
175 | merge
176 | (fn [_v1 v2] v2))))
177 |
178 | (defn- merge-alias-maps
179 | "Like merge-with, but using custom per-alias-key merge function"
180 | [& ms]
181 | (reduce
182 | #(reduce
183 | (fn [m [k v]] (update m k (choose-rule k v) v))
184 | %1 %2)
185 | {} ms))
186 |
187 | (defn combine-aliases
188 | "Find, read, and combine alias maps identified by alias keywords from
189 | a deps edn map into a single args map."
190 | [edn-map alias-kws]
191 | (->> alias-kws
192 | (map #(get-in edn-map [:aliases %]))
193 | (apply merge-alias-maps)))
194 |
195 |
196 |
197 |
198 | (defn- chase-key
199 | "Given an aliases set and a keyword k, return a flattened vector of path
200 | entries for that k, resolving recursively if needed, or nil."
201 | [aliases k]
202 | (let [path-coll (get aliases k)]
203 | (when (seq path-coll)
204 | (into [] (mapcat #(if (string? %) [[% {:path-key k}]] (chase-key aliases %))) path-coll))))
205 |
206 | (defn- flatten-paths
207 | [{:keys [paths aliases] :as deps-edn-map} {:keys [extra-paths] :as classpath-args}]
208 | (let [aliases' (assoc aliases :paths paths :extra-paths extra-paths)]
209 | (into [] (comp (mapcat #(chase-key aliases' %)) (remove nil?)) [:extra-paths :paths])))
210 |
211 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates'
19 | from a Contributor if it was added to the Program by such Contributor
20 | itself or anyone acting on such Contributor's behalf. Contributions do not
21 | include additions to the Program which: (i) are separate modules of
22 | software distributed in conjunction with the Program under their own
23 | license agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this
32 | Agreement.
33 |
34 | "Recipient" means anyone who receives the Program under this Agreement,
35 | including all Contributors.
36 |
37 | 2. GRANT OF RIGHTS
38 | a) Subject to the terms of this Agreement, each Contributor hereby grants
39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
40 | reproduce, prepare derivative works of, publicly display, publicly
41 | perform, distribute and sublicense the Contribution of such Contributor,
42 | if any, and such derivative works, in source code and object code form.
43 | b) Subject to the terms of this Agreement, each Contributor hereby grants
44 | Recipient a non-exclusive, worldwide, royalty-free patent license under
45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
46 | transfer the Contribution of such Contributor, if any, in source code and
47 | object code form. This patent license shall apply to the combination of
48 | the Contribution and the Program if, at the time the Contribution is
49 | added by the Contributor, such addition of the Contribution causes such
50 | combination to be covered by the Licensed Patents. The patent license
51 | shall not apply to any other combinations which include the Contribution.
52 | No hardware per se is licensed hereunder.
53 | c) Recipient understands that although each Contributor grants the licenses
54 | to its Contributions set forth herein, no assurances are provided by any
55 | Contributor that the Program does not infringe the patent or other
56 | intellectual property rights of any other entity. Each Contributor
57 | disclaims any liability to Recipient for claims brought by any other
58 | entity based on infringement of intellectual property rights or
59 | otherwise. As a condition to exercising the rights and licenses granted
60 | hereunder, each Recipient hereby assumes sole responsibility to secure
61 | any other intellectual property rights needed, if any. For example, if a
62 | third party patent license is required to allow Recipient to distribute
63 | the Program, it is Recipient's responsibility to acquire that license
64 | before distributing the Program.
65 | d) Each Contributor represents that to its knowledge it has sufficient
66 | copyright rights in its Contribution, if any, to grant the copyright
67 | license set forth in this Agreement.
68 |
69 | 3. REQUIREMENTS
70 |
71 | A Contributor may choose to distribute the Program in object code form under
72 | its own license agreement, provided that:
73 |
74 | a) it complies with the terms and conditions of this Agreement; and
75 | b) its license agreement:
76 | i) effectively disclaims on behalf of all Contributors all warranties
77 | and conditions, express and implied, including warranties or
78 | conditions of title and non-infringement, and implied warranties or
79 | conditions of merchantability and fitness for a particular purpose;
80 | ii) effectively excludes on behalf of all Contributors all liability for
81 | damages, including direct, indirect, special, incidental and
82 | consequential damages, such as lost profits;
83 | iii) states that any provisions which differ from this Agreement are
84 | offered by that Contributor alone and not by any other party; and
85 | iv) states that source code for the Program is available from such
86 | Contributor, and informs licensees how to obtain it in a reasonable
87 | manner on or through a medium customarily used for software exchange.
88 |
89 | When the Program is made available in source code form:
90 |
91 | a) it must be made available under this Agreement; and
92 | b) a copy of this Agreement must be included with each copy of the Program.
93 | Contributors may not remove or alter any copyright notices contained
94 | within the Program.
95 |
96 | Each Contributor must identify itself as the originator of its Contribution,
97 | if
98 | any, in a manner that reasonably allows subsequent Recipients to identify the
99 | originator of the Contribution.
100 |
101 | 4. COMMERCIAL DISTRIBUTION
102 |
103 | Commercial distributors of software may accept certain responsibilities with
104 | respect to end users, business partners and the like. While this license is
105 | intended to facilitate the commercial use of the Program, the Contributor who
106 | includes the Program in a commercial product offering should do so in a manner
107 | which does not create potential liability for other Contributors. Therefore,
108 | if a Contributor includes the Program in a commercial product offering, such
109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
110 | every other Contributor ("Indemnified Contributor") against any losses,
111 | damages and costs (collectively "Losses") arising from claims, lawsuits and
112 | other legal actions brought by a third party against the Indemnified
113 | Contributor to the extent caused by the acts or omissions of such Commercial
114 | Contributor in connection with its distribution of the Program in a commercial
115 | product offering. The obligations in this section do not apply to any claims
116 | or Losses relating to any actual or alleged intellectual property
117 | infringement. In order to qualify, an Indemnified Contributor must:
118 | a) promptly notify the Commercial Contributor in writing of such claim, and
119 | b) allow the Commercial Contributor to control, and cooperate with the
120 | Commercial Contributor in, the defense and any related settlement
121 | negotiations. The Indemnified Contributor may participate in any such claim at
122 | its own expense.
123 |
124 | For example, a Contributor might include the Program in a commercial product
125 | offering, Product X. That Contributor is then a Commercial Contributor. If
126 | that Commercial Contributor then makes performance claims, or offers
127 | warranties related to Product X, those performance claims and warranties are
128 | such Commercial Contributor's responsibility alone. Under this section, the
129 | Commercial Contributor would have to defend claims against the other
130 | Contributors related to those performance claims and warranties, and if a
131 | court requires any other Contributor to pay any damages as a result, the
132 | Commercial Contributor must pay those damages.
133 |
134 | 5. NO WARRANTY
135 |
136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
140 | Recipient is solely responsible for determining the appropriateness of using
141 | and distributing the Program and assumes all risks associated with its
142 | exercise of rights under this Agreement , including but not limited to the
143 | risks and costs of program errors, compliance with applicable laws, damage to
144 | or loss of data, programs or equipment, and unavailability or interruption of
145 | operations.
146 |
147 | 6. DISCLAIMER OF LIABILITY
148 |
149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
156 | OF SUCH DAMAGES.
157 |
158 | 7. GENERAL
159 |
160 | If any provision of this Agreement is invalid or unenforceable under
161 | applicable law, it shall not affect the validity or enforceability of the
162 | remainder of the terms of this Agreement, and without further action by the
163 | parties hereto, such provision shall be reformed to the minimum extent
164 | necessary to make such provision valid and enforceable.
165 |
166 | If Recipient institutes patent litigation against any entity (including a
167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
168 | (excluding combinations of the Program with other software or hardware)
169 | infringes such Recipient's patent(s), then such Recipient's rights granted
170 | under Section 2(b) shall terminate as of the date such litigation is filed.
171 |
172 | All Recipient's rights under this Agreement shall terminate if it fails to
173 | comply with any of the material terms or conditions of this Agreement and does
174 | not cure such failure in a reasonable period of time after becoming aware of
175 | such noncompliance. If all Recipient's rights under this Agreement terminate,
176 | Recipient agrees to cease use and distribution of the Program as soon as
177 | reasonably practicable. However, Recipient's obligations under this Agreement
178 | and any licenses granted by Recipient relating to the Program shall continue
179 | and survive.
180 |
181 | Everyone is permitted to copy and distribute copies of this Agreement, but in
182 | order to avoid inconsistency the Agreement is copyrighted and may only be
183 | modified in the following manner. The Agreement Steward reserves the right to
184 | publish new versions (including revisions) of this Agreement from time to
185 | time. No one other than the Agreement Steward has the right to modify this
186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
187 | Eclipse Foundation may assign the responsibility to serve as the Agreement
188 | Steward to a suitable separate entity. Each new version of the Agreement will
189 | be given a distinguishing version number. The Program (including
190 | Contributions) may always be distributed subject to the version of the
191 | Agreement under which it was received. In addition, after a new version of the
192 | Agreement is published, Contributor may elect to distribute the Program
193 | (including its Contributions) under the new version. Except as expressly
194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
195 | licenses to the intellectual property of any Contributor under this Agreement,
196 | whether expressly, by implication, estoppel or otherwise. All rights in the
197 | Program not expressly granted under this Agreement are reserved.
198 |
199 | This Agreement is governed by the laws of the State of New York and the
200 | intellectual property laws of the United States of America. No party to this
201 | Agreement will bring a legal action under this Agreement more than one year
202 | after the cause of action arose. Each party waives its rights to a jury trial in
203 | any resulting litigation.
204 |
205 |
206 |
--------------------------------------------------------------------------------