├── VERSION_TEMPLATE ├── .gitignore ├── .github └── workflows │ ├── snapshot.yml │ ├── doc-build.yml │ ├── release.yml │ └── test.yml ├── script └── version ├── CONTRIBUTING.md ├── deps.edn ├── README.md ├── CHANGELOG.md ├── pom.xml ├── src ├── main │ └── clojure │ │ └── clojure │ │ └── tools │ │ └── deps │ │ └── cli │ │ ├── help.clj │ │ └── api.clj └── test │ └── clojure │ └── clojure │ └── tools │ └── deps │ └── cli │ └── test_api.clj └── LICENSE /VERSION_TEMPLATE: -------------------------------------------------------------------------------- 1 | 0.14.GENERATED_VERSION 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/workflows/snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Snapshot on demand 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: [workflow_dispatch] 7 | 8 | jobs: 9 | call-snapshot: 10 | uses: clojure/build.ci/.github/workflows/snapshot.yml@master 11 | secrets: inherit 12 | -------------------------------------------------------------------------------- /.github/workflows/doc-build.yml: -------------------------------------------------------------------------------- 1 | name: Build API Docs 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | call-doc-build-workflow: 11 | uses: clojure/build.ci/.github/workflows/doc-build.yml@master 12 | with: 13 | project: clojure/tools.deps.cli 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src/main/clojure" "src/main/resources"] 2 | :deps { 3 | org.clojure/clojure {:mvn/version "1.12.4"} 4 | org.clojure/tools.deps {:mvn/version "0.27.1560"} 5 | } 6 | :aliases { 7 | ;; clj -M:lint 8 | :lint {:replace-deps {clj-kondo/clj-kondo {:mvn/version "2025.07.28"}} 9 | :main-opts ["-m" "clj-kondo.main" "--lint" "src/main/clojure" "--lint" "src/test/clojure"]} 10 | 11 | ;; clj -M:outdated 12 | :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "RELEASE"}} 13 | :main-opts ["-m" "antq.core"]} 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release on demand 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | workflow_dispatch: 8 | inputs: 9 | releaseVersion: 10 | description: "Version to release" 11 | required: true 12 | snapshotVersion: 13 | description: "Snapshot version after release" 14 | required: true 15 | 16 | jobs: 17 | call-release: 18 | uses: clojure/build.ci/.github/workflows/release.yml@master 19 | with: 20 | releaseVersion: ${{ github.event.inputs.releaseVersion }} 21 | snapshotVersion: ${{ github.event.inputs.snapshotVersion }} 22 | secrets: inherit -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: [push] 7 | 8 | jobs: 9 | test: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] # macOS-latest, windows-latest] 13 | java-version: ["8", "11", "17"] 14 | clojure-version: ["1.11.1"] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v5 18 | - name: Set up Java 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: ${{ matrix.java-version }} 22 | distribution: 'temurin' 23 | cache: 'maven' 24 | - name: Build with Maven 25 | run: mvn -ntp -B -Dclojure.version=${{ matrix.clojure-version }} clean test 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tools.deps.cli 2 | ======================================== 3 | 4 | Deps programs for use via the Clojure CLI. The Clojure CLI ships with a standard alias `:deps` that can be used to get access to these programs. 5 | 6 | Also see: 7 | 8 | * [Deps and CLI Reference - Other programs](https://clojure.org/reference/clojure_cli#programs) 9 | * [API](https://clojure.github.io/tools.deps.cli) 10 | 11 | # Release Information 12 | 13 | Latest release: 0.14.121 14 | 15 | * [All released versions](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22tools.deps.cli%22) 16 | 17 | [deps.edn](https://clojure.org/guides/deps_and_cli) dependency information: 18 | 19 | ``` 20 | org.clojure/tools.deps.cli {:mvn/version "0.14.121"} 21 | ``` 22 | 23 | # Developer Information 24 | 25 | * [GitHub project](https://github.com/clojure/tools.deps.cli) 26 | * [How to contribute](https://clojure.org/community/contributing) 27 | * [Bug Tracker](https://clojure.atlassian.net/browse/TDEPS) 28 | * [Continuous Integration](https://github.com/clojure/tools.deps.cli/actions/workflows/test.yml) 29 | 30 | # Copyright and License 31 | 32 | Copyright © Rich Hickey, Alex Miller, and contributors 33 | 34 | All rights reserved. The use and 35 | distribution terms for this software are covered by the 36 | [Eclipse Public License 1.0] which can be found in the file 37 | LICENSE at the root of this distribution. By using this software 38 | in any fashion, you are agreeing to be bound by the terms of this 39 | license. You must not remove this notice, or any other, from this 40 | software. 41 | 42 | [Eclipse Public License 1.0]: https://opensource.org/license/epl-1-0/ 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | =========== 3 | 4 | * 0.14.121 on Dec 10, 2025 5 | * Update to latest Clojure and tools.deps 6 | * 0.13.115 on Sep 25, 2025 7 | * Update to latest deps 8 | * 0.12.110 on Sep 22, 2025 9 | * TDEPS-272 - `prep` now supports prep of named tool 10 | * Update to latest deps 11 | * 0.12.105 on Aug 26, 2025 12 | * Update to Clojure 1.12.2 and latest tools.deps 13 | * 0.11.100 on Aug 14, 2025 14 | * TDEPS-264 - Add `basis` program 15 | * Update mvn-install docstring example 16 | * 0.11.93 on Jun 3, 2025 17 | * Update to latest tools.deps and Clojure 1.12.1 18 | * Update to latest clj-kondo and fix lint warnings 19 | * 0.11.86 on Feb 7, 2025 20 | * Update to latest tools.deps 21 | * 0.11.78 on Nov 21, 2024 22 | * TDEPS-268 - Return all procurer types from find-versions 23 | * Update to latest tools.deps 24 | * 0.11.72 on Sep 5, 2024 25 | * Update to latest Clojure and tools.deps 26 | * 0.10.66 on May 1, 2024 27 | * aliases - ignore aliases with non-map data 28 | * Update to latest tools.deps 29 | * 0.10.61 on Apr 24, 2024 30 | * Update to latest tools.deps and Clojure 1.11.3 31 | * 0.10.55 on Mar 8, 2024 32 | * Update to latest tools.deps and Clojure 1.11.2 33 | * Add new :dir option to all programs that use create-basis 34 | * 0.9.49 on Dec 29, 2023 35 | * Update to latest tools.deps 36 | * 0.9.43 on May 31, 2023 37 | * Update to latest tools.deps 38 | * 0.9.35 on Mar 30, 2023 39 | * Update to latest tools.deps 40 | * 0.9.30 on Mar 27, 2023 41 | * Update to latest tools.deps 42 | * 0.9.26 on Mar 15, 2023 43 | * Update to latest tools.deps 44 | * 0.9.21 on Mar 13, 2023 45 | * Update to latest tools.deps 46 | * 0.9.17 on Mar 7, 2023 47 | * Update to latest tools.deps 48 | * 0.9.10 on Dec 9, 2022 49 | * Split out of tools.deps.alpha and updated namespaces 50 | 51 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | tools.deps.cli 4 | 0.14.122-SNAPSHOT 5 | tools.deps.cli 6 | Dependency programs for use via the Clojure CLI. 7 | 8 | 9 | org.clojure 10 | pom.contrib 11 | 1.3.0 12 | 13 | 14 | 15 | 16 | puredanger 17 | Alex Miller 18 | 19 | 20 | 21 | 22 | 23 | true 24 | 1.12.2 25 | 26 | 27 | 28 | 29 | org.clojure 30 | clojure 31 | ${clojure.version} 32 | 33 | 34 | org.clojure 35 | tools.deps 36 | 0.25.1539 37 | 38 | 39 | org.slf4j 40 | slf4j-nop 41 | 1.7.36 42 | 43 | 44 | 45 | 46 | 47 | 48 | src/main/resources 49 | true 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-resources-plugin 56 | 3.1.0 57 | 58 | 59 | 62 | com.theoryinpractise 63 | clojure-maven-plugin 64 | 1.7.1 65 | true 66 | 67 | ${clojure.warnOnReflection} 68 | true 69 | 70 | 71 | 72 | clojure-compile 73 | none 74 | 75 | 76 | clojure-test 77 | test 78 | 79 | test 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | scm:git:git@github.com:clojure/tools.deps.cli.git 89 | scm:git:git@github.com:clojure/tools.deps.cli.git 90 | git@github.com:clojure/tools.deps.cli.git 91 | HEAD 92 | 93 | 94 | 95 | 96 | clojars 97 | https://clojars.org/repo/ 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/tools/deps/cli/help.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.cli.help 10 | (:require 11 | [clojure.string :as str] 12 | [clojure.repl :as repl])) 13 | 14 | (defn- garner-ns-defaults [] 15 | (try 16 | (require 'clojure.run.exec) 17 | (let [nsd (some-> "clojure.run.exec/*ns-default*" symbol resolve deref) 18 | nsa (some-> "clojure.run.exec/*ns-aliases*" symbol resolve deref)] 19 | (cond-> {} 20 | nsd (assoc :ns-default nsd) 21 | nsa (assoc :ns-aliases nsa))) 22 | (catch Exception e 23 | (throw (ex-info (.getMessage e) {} e))))) 24 | 25 | (defn- qualify-fn 26 | "Compute function symbol based on exec-fn, ns-aliases, and ns-default" 27 | [fsym ns-aliases ns-default] 28 | ;; validation - make specs? 29 | (when (and fsym (not (symbol? fsym))) 30 | (throw (ex-info (str "Expected function symbol:" fsym) {}))) 31 | 32 | (when fsym 33 | (if (qualified-ident? fsym) 34 | (let [nsym (get ns-aliases (symbol (namespace fsym)))] 35 | (if nsym 36 | (symbol (str nsym) (name fsym)) 37 | fsym)) 38 | (if ns-default 39 | (symbol (str ns-default) (str fsym)) 40 | (throw (ex-info (str "Unqualified function can't be resolved:" fsym) {})))))) 41 | 42 | (defn doc 43 | "Print doc for the specified namespace or function. If neither is specified, print docs 44 | for :ns-default. 45 | 46 | Options: 47 | :ns Print docs for namespace 48 | :fn Print docs for function" 49 | [{:keys [ns fn] :as args}] 50 | (let [{:keys [ns-default ns-aliases]} (merge args (garner-ns-defaults))] 51 | (if fn 52 | (#'repl/print-doc (meta (requiring-resolve (qualify-fn fn ns-aliases ns-default)))) 53 | (let [ns-maybe (or ns ns-default) 54 | ns (if ns-aliases (get ns-aliases ns-maybe ns-maybe) ns-maybe)] 55 | (when (nil? ns) 56 | (throw (ex-info "No namespace or function specified" {}))) 57 | (require ns) 58 | (let [my-ns (the-ns ns) 59 | ns-doc (:doc (meta my-ns))] 60 | ;; Print namespace docs 61 | (when (not (str/blank? ns-doc)) 62 | (println ns-doc) 63 | (println)) 64 | ;; Print function docs 65 | (doseq [[_k v] (->> my-ns ns-publics (sort-by key))] 66 | (when (instance? clojure.lang.Fn @v) 67 | (#'repl/print-doc (meta v))))))))) 68 | 69 | (defn dir 70 | "Prints a sorted directory of public vars in a namespace. If a namespace is not 71 | specified :ns-default is used instead." 72 | [{:keys [ns] :as args}] 73 | (let [{:keys [ns-default ns-aliases]} (merge args (garner-ns-defaults)) 74 | ns-maybe (or ns ns-default) 75 | ns (if ns-aliases (get ns-aliases ns-maybe ns-maybe) ns-maybe) 76 | _ (require ns) 77 | my-ns (the-ns ns)] 78 | (doseq [[s v] (->> my-ns ns-publics (sort-by key))] 79 | (when (instance? clojure.lang.Fn @v) 80 | (println s))))) 81 | 82 | (comment 83 | (doc {:ns 'clojure.tools.cli.help}) 84 | (doc {:fn 'clojure.tools.cli.help/doc}) 85 | (dir {:ns 'clojure.tools.cli.help}) 86 | ) 87 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/tools/deps/cli/test_api.clj: -------------------------------------------------------------------------------- 1 | (ns clojure.tools.deps.cli.test-api 2 | (:require 3 | [clojure.edn :as edn] 4 | [clojure.java.io :as jio] 5 | [clojure.string :as str] 6 | [clojure.test :refer [deftest is] :as test] 7 | [clojure.tools.deps.cli.api :as api] 8 | [clojure.tools.deps] ;; ensure extensions loaded 9 | [clojure.tools.deps.util.maven :as mvn] 10 | [clojure.tools.deps.util.dir :as dir]) 11 | (:import 12 | [java.io File])) 13 | 14 | (def ^:dynamic ^File *test-dir* nil) 15 | 16 | (defmacro with-test-dir 17 | [& body] 18 | `(let [name# (-> test/*testing-vars* last symbol str) 19 | dir# (jio/file "test-out" name#)] 20 | (.delete dir#) 21 | (.mkdirs dir#) 22 | (binding [*test-dir* dir#] 23 | ~@body))) 24 | 25 | (deftest test-aliases-with-non-map-data 26 | (with-test-dir 27 | (let [p1deps (jio/file *test-dir* "p1/deps.edn")] 28 | (jio/make-parents p1deps) 29 | (spit p1deps 30 | (pr-str {:aliases {:foo ["some" "data"]}})) 31 | 32 | (dir/with-dir (jio/file *test-dir* "p1") 33 | (let [output (with-out-str (api/aliases {:user nil}))] 34 | (is (str/includes? output ":deps")) 35 | (is (not (str/includes? output ":foo")))))))) 36 | 37 | (deftest test-prep-with-aliases 38 | (with-test-dir 39 | (let [p1deps (jio/file *test-dir* "p1/deps.edn") 40 | p2deps (jio/file *test-dir* "p2/deps.edn")] 41 | 42 | ;; set up p1 with an alias that, if used, pulls p2 43 | (jio/make-parents p1deps) 44 | (spit p1deps 45 | (pr-str {:aliases {:x {:extra-deps {'foo/bar {:local/root "../p2"}}}}})) 46 | 47 | ;; set up p2 to prep 48 | (jio/make-parents p2deps) 49 | (spit (jio/file *test-dir* "p2/build.clj") 50 | "(ns build 51 | (:require [clojure.java.io :as jio])) 52 | (defn prep [_] 53 | (jio/make-parents \"prepped/out\"))") 54 | (spit p2deps 55 | (pr-str {:deps/prep-lib {:ensure "prepped" 56 | :alias :build 57 | :fn 'prep} 58 | :aliases {:build {:ns-default 'build}}})) 59 | 60 | ;; prep p1 with aliases 61 | (dir/with-dir (jio/file *test-dir* "p1") 62 | (api/prep 63 | {:root {:mvn/repos mvn/standard-repos} 64 | :user nil 65 | :project :standard 66 | :aliases [:x] 67 | :force true})) 68 | 69 | ;; check that it prepped p2 70 | (is (true? (.exists (jio/file *test-dir* "p2/prepped"))))))) 71 | 72 | 73 | (deftest test-prep-across-modules 74 | (with-test-dir 75 | (spit (jio/file *test-dir* "deps.edn") 76 | (pr-str {:deps {'mono/moda {:local/root "mod/a"} 77 | 'mono/modb {:local/root "mod/b"}}})) 78 | (let [adeps (jio/file *test-dir* "mod/a/deps.edn")] 79 | (jio/make-parents adeps) 80 | (spit adeps "{}")) 81 | (let [bdeps (jio/file *test-dir* "mod/b/deps.edn")] 82 | (jio/make-parents bdeps) 83 | (spit bdeps 84 | (pr-str {:paths ["src"] 85 | :deps/prep-lib {:alias :resources 86 | :fn 'bcore/generate 87 | :ensure "target/resources"} 88 | :aliases {:resources {:deps {'mono/moda {:local/root "../a"}} :paths ["src"]}}}))) 89 | (let [bgen (jio/file *test-dir* "mod/b/src/bcore.clj") 90 | cp-path (.getCanonicalPath (jio/file *test-dir* "mod/b/target/resources/cp"))] 91 | (jio/make-parents bgen) 92 | (spit bgen 93 | (str 94 | "(ns bcore)" 95 | (format "(defn generate [_] (.mkdirs (.getParentFile (java.io.File. \"%s\"))) (spit \"%s\" (System/getProperty \"java.class.path\")))" 96 | cp-path cp-path))) 97 | (api/prep 98 | {:root {:mvn/repos mvn/standard-repos} 99 | :user nil 100 | :project {:deps {'org.clojure/clojure {:mvn/version "1.11.1"} 101 | 'mono/root {:local/root (.getPath *test-dir*)}}} 102 | ;; :log :debug 103 | :force true}) 104 | (let [cp-out (slurp cp-path)] 105 | (is (true? (str/includes? cp-out (.getCanonicalPath (jio/file *test-dir* "mod/a/src"))))))))) 106 | 107 | (deftest test-prep-exec-args 108 | (with-test-dir 109 | (let [p1deps (jio/file *test-dir* "p1/deps.edn") 110 | p2deps (jio/file *test-dir* "p2/deps.edn")] 111 | 112 | ;; set up p1 to depend on p2 113 | (jio/make-parents p1deps) 114 | (spit p1deps (pr-str {:deps {'foo/p2 {:local/root "../p2"}}})) 115 | 116 | ;; set up p2 to prep 117 | (jio/make-parents p2deps) 118 | (spit (jio/file *test-dir* "p2/build.clj") 119 | "(ns build 120 | (:require [clojure.java.io :as jio])) 121 | (defn prep [args] 122 | (jio/make-parents \"prepped/out\") 123 | (spit \"prepped/out\" args))") 124 | (spit p2deps 125 | (pr-str {:deps/prep-lib {:ensure "prepped" 126 | :alias :build 127 | :fn 'prep} 128 | :aliases {:build {:ns-default 'build 129 | :exec-args {:hi :there}}}})) 130 | 131 | ;; prep p1 with aliases 132 | (dir/with-dir (jio/file *test-dir* "p1") 133 | (api/prep 134 | {:root {:mvn/repos mvn/standard-repos} 135 | :user nil 136 | :project :standard 137 | :force true})) 138 | 139 | ;; check that it prepped p2 and received the args 140 | (is (= "{:hi :there}" (slurp (jio/file *test-dir* "p2/prepped/out"))))))) 141 | 142 | (deftest test-self-prep 143 | (with-test-dir 144 | (let [p1deps (jio/file *test-dir* "p1/deps.edn") 145 | p2deps (jio/file *test-dir* "p2/deps.edn")] 146 | 147 | ;; set up p1 to depend on p2 but also need self prep 148 | (jio/make-parents p1deps) 149 | (spit (jio/file *test-dir* "p1/build.clj") 150 | "(ns build 151 | (:require [clojure.java.io :as jio])) 152 | (defn prep [args] 153 | (jio/make-parents \"prepped/out\"))") 154 | (spit p1deps 155 | (pr-str {:deps {'foo/p2 {:local/root "../p2"}} 156 | :deps/prep-lib {:ensure "prepped" 157 | :alias :build 158 | :fn 'prep} 159 | :aliases {:build {:ns-default 'build}}})) 160 | 161 | ;; set up p2 to prep 162 | (jio/make-parents p2deps) 163 | (spit (jio/file *test-dir* "p2/build.clj") 164 | "(ns build 165 | (:require [clojure.java.io :as jio])) 166 | (defn prep [args] 167 | (jio/make-parents \"prepped/out\"))") 168 | (spit p2deps 169 | (pr-str {:deps/prep-lib {:ensure "prepped" 170 | :alias :build 171 | :fn 'prep} 172 | :aliases {:build {:ns-default 'build}}})) 173 | 174 | ;; prep p1 175 | (dir/with-dir (jio/file *test-dir* "p1") 176 | (api/prep 177 | {:root {:mvn/repos mvn/standard-repos} 178 | :user nil 179 | :project :standard 180 | ;; :log :debug 181 | :force true 182 | :current true})) 183 | 184 | ;; check that it prepped p1 and p2 185 | (is (true? (.exists (jio/file *test-dir* "p1/prepped")))) 186 | (is (true? (.exists (jio/file *test-dir* "p2/prepped"))))))) 187 | 188 | (deftest test-find-maven-version 189 | (let [s (with-out-str (api/find-versions {:lib 'org.clojure/clojure :n :all}))] 190 | (is (str/includes? s "1.10.3"))) 191 | 192 | (is (= "" (with-out-str (api/find-versions {:lib 'bogus.taco/slurpee}))))) 193 | 194 | (deftest test-find-git-version 195 | (let [s (with-out-str (api/find-versions {:lib 'io.github.clojure/tools.build :n :all}))] 196 | (is (str/includes? s "v0.8.2"))) 197 | 198 | (is (= "" (with-out-str (api/find-versions {:lib 'io.github.clojure/bogus-taco-slurpee}))))) 199 | 200 | (deftest test-find-versions-returns-results-from-all-procurers 201 | (let [expected [[:git/tag :git/sha] [:mvn/version]] 202 | actual (->> (api/find-versions {:lib 'io.github.clojure/tools.build :n 4}) 203 | with-out-str 204 | str/split-lines 205 | (map edn/read-string) 206 | (group-by keys) 207 | keys)] 208 | (is (= expected actual)))) 209 | 210 | (comment 211 | (test-find-maven-version) 212 | (test-find-git-version) 213 | ) 214 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/tools/deps/cli/api.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.cli.api 10 | "This api provides functions that can be executed from the Clojure tools using -X:deps." 11 | (:refer-clojure :exclude [list]) 12 | (:require 13 | [clojure.edn :as edn] 14 | [clojure.java.io :as jio] 15 | [clojure.pprint :as pprint] 16 | [clojure.string :as str] 17 | [clojure.tools.deps :as deps] 18 | [clojure.tools.deps.tool :as tool] 19 | [clojure.tools.deps.tree :as tree] 20 | [clojure.tools.deps.script.resolve-tags :as resolve-tags] 21 | [clojure.tools.deps.extensions :as ext] 22 | [clojure.tools.deps.extensions.pom :as pom] 23 | [clojure.tools.deps.extensions.local :as local] 24 | [clojure.tools.deps.gen.pom :as gen-pom] 25 | [clojure.tools.deps.util.maven :as mvn] 26 | [clojure.tools.deps.util.io :as io :refer [printerrln]] 27 | [clojure.set :as set]) 28 | (:import 29 | [java.io File FileNotFoundException IOException] 30 | [java.nio.file Files] 31 | [java.nio.file.attribute FileAttribute] 32 | [java.util.jar JarFile] 33 | [org.apache.maven.model Model] 34 | [org.eclipse.aether.artifact DefaultArtifact] 35 | [org.eclipse.aether.installation InstallRequest] 36 | [clojure.lang IExceptionInfo])) 37 | 38 | (set! *warn-on-reflection* true) 39 | 40 | (defn basis 41 | "Print basis, by default using the same settings as the CLI for the current project. 42 | 43 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 44 | Sources are merged in the order - :root, :user, :project, :extra. 45 | 46 | Basis options: 47 | :dir - directory root path, defaults to current directory 48 | :root - dep source, default = :standard 49 | :user - dep source, default = :standard 50 | :project - dep source, default = :standard (\"./deps.edn\") 51 | :extra - dep source, default = nil 52 | :aliases - coll of kw aliases of argmaps to apply to subprocesses" 53 | [opts] 54 | (let [basis (deps/create-basis opts)] 55 | (binding [*print-namespace-maps* false] 56 | (pprint/pprint basis)))) 57 | 58 | (defn prep 59 | "Prep the unprepped libs found in the transitive lib set of basis. 60 | 61 | This program accepts the same basis-modifying arguments from the `basis` program. 62 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 63 | Sources are merged in the order - :root, :user, :project, :extra. Alternately, 64 | provide a :tool name to prep the libs for a tool. 65 | 66 | Options: 67 | :tool - Tool name (symbol or string) to prep installed tool 68 | :force - flag on whether to force prepped libs to re-prep (default = false) 69 | :current - flag on whether to prep current project too (default = false) 70 | :log - :none, :info (default), or :debug 71 | 72 | Basis options: 73 | :dir - directory root path, defaults to current directory 74 | :root - dep source, default = :standard 75 | :user - dep source, default = :standard 76 | :project - dep source, default = :standard (\"./deps.edn\") 77 | :extra - dep source, default = nil 78 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 79 | 80 | Returns params used." 81 | [{:keys [force log current tool] :or {log :info, current false} :as params}] 82 | (let [opts {:action (if force :force :prep) 83 | :log log 84 | :current current} 85 | params (if tool 86 | (if-let [{:keys [lib coord]} (tool/resolve-tool (name tool))] 87 | {:project nil, :args {:deps {lib coord}}} 88 | (throw (ex-info (str "Unknown tool: " tool) {:tool tool}))) 89 | params) 90 | basis (deps/create-basis params)] 91 | (deps/prep-libs! (:libs basis) opts basis) 92 | params)) 93 | 94 | (comment 95 | (do 96 | (prep 97 | {:root {:mvn/repos mvn/standard-repos, :deps nil} 98 | :project {:deps '{org.clojure/clojure {:mvn/version "1.10.3"} 99 | io.github.puredanger/cool-lib 100 | {:git/sha "657d5ce88be340ab2a6c0befeae998366105be84"}}} 101 | :log :debug 102 | :force true}) 103 | nil) 104 | 105 | (do 106 | (prep 107 | {:root {:mvn/repos mvn/standard-repos, :deps nil} 108 | :tool 'eden 109 | :log :debug 110 | :force true})) 111 | ) 112 | 113 | (defn tree 114 | "Print deps tree for the current project's deps.edn built from either the 115 | a basis, or if provided, the trace file. 116 | 117 | This program accepts the same basis-modifying arguments from the `basis` program. 118 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 119 | Sources are merged in the order - :root, :user, :project, :extra. 120 | 121 | By default, :format will :print to the console in a human friendly tree. Use 122 | :edn mode to print the tree to edn. 123 | 124 | In print mode, deps are printed with prefix of either . (included) or X (excluded). 125 | A reason code for inclusion/exclusion may be added at the end of the line. 126 | 127 | Basis options: 128 | :dir - directory root path, defaults to current directory 129 | :root - dep source, default = :standard 130 | :user - dep source, default = :standard 131 | :project - dep source, default = :standard (\"./deps.edn\") 132 | :extra - dep source, default = nil 133 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 134 | 135 | Input options (if provided, basis options ignored): 136 | :file Path to trace.edn file (from clj -Strace) to use in computing the tree 137 | 138 | Output mode: 139 | :format :print (default) or :edn 140 | 141 | Print output mode modifiers: 142 | :indent Indent spacing (default = 2) 143 | :hide-libs Set of libs to hide as deps (if not top dep), default = #{org.clojure/clojure}" 144 | [opts] 145 | (try 146 | (let [{:keys [file format] :or {format :print}} opts 147 | trace (if file 148 | (io/slurp-edn file) 149 | (tree/calc-trace opts)) 150 | tree (tree/trace->tree trace)] 151 | (case format 152 | :print (tree/print-tree tree opts) 153 | :edn (pprint/pprint tree) 154 | (throw (ex-info (str "Unknown format " format) {})))) 155 | (catch Throwable t 156 | (printerrln "Error generating tree:" (.getMessage t)) 157 | (when-not (instance? IExceptionInfo t) 158 | (.printStackTrace t)) 159 | (System/exit 1)))) 160 | 161 | (comment 162 | (tree nil) 163 | (tree {:extra {:aliases {:foo {:extra-deps {'criterium/criterium {:mvn/version "0.4.0"}}}}} 164 | :aliases [:foo]}) 165 | ) 166 | 167 | (def ^:private cli-alias-keys 168 | #{:deps :replace-deps :extra-deps :override-deps :default-deps 169 | :paths :replace-paths :extra-paths :classpath-overrides 170 | :exec-fn :exec-args :ns-default :ns-aliases 171 | :main-opts :jvm-opts}) 172 | 173 | (defn aliases 174 | "List all aliases available for use with the CLI using -M, -X or -T execution 175 | (note that some aliases may be usable with more than one of these). Also, the 176 | deps.edn sources of the alias are specified. 177 | 178 | This program accepts the same basis-modifying arguments from the `basis` program. 179 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 180 | Sources are merged in the order - :root, :user, :project, :extra. 181 | 182 | For example, to print only aliases defined in this project: 183 | clj -X:deps aliases :root nil :user nil 184 | 185 | Basis options: 186 | :root - dep source, default = :standard 187 | :user - dep source, default = :standard 188 | :project - dep source, default = :standard (\"./deps.edn\") 189 | :extra - dep source, default = nil 190 | 191 | The aliases are printed to the console." 192 | [params] 193 | (let [edn-srcs (deps/create-edn-maps params) 194 | src-aliases (reduce-kv #(assoc %1 %2 (:aliases %3)) {} edn-srcs) 195 | cli-aliases (reduce-kv 196 | (fn [m src aliases] 197 | (assoc m 198 | src 199 | (reduce-kv 200 | (fn [a alias alias-defn] 201 | (cond-> a 202 | (pos? (count (set/intersection cli-alias-keys (when (map? alias-defn) (set (keys alias-defn)))))) 203 | (assoc alias alias-defn))) 204 | {} aliases))) 205 | {} src-aliases) 206 | all-aliases (->> cli-aliases (map val) (mapcat #(-> % keys sort)) distinct)] 207 | (doseq [alias all-aliases] 208 | (let [srcs (reduce-kv (fn [srcs src deps-edn] 209 | (if (contains? (:aliases deps-edn) alias) 210 | (conj srcs src) 211 | srcs)) 212 | [] edn-srcs)] 213 | (println alias (str "(" (str/join ", " (map name srcs)) ")")))))) 214 | 215 | (def ^:private license-abbrev 216 | (delay 217 | (-> "clojure/tools/deps/license-abbrev.edn" jio/resource slurp edn/read-string))) 218 | 219 | (defn- license-string 220 | [info license-mode] 221 | (let [abbrevs @license-abbrev 222 | license-name (when (#{:full :short} license-mode) (:name info))] 223 | (if (and license-name (= license-mode :short)) 224 | (get abbrevs license-name license-name) 225 | license-name))) 226 | 227 | (defn list 228 | "List all deps on the classpath, optimized for knowing the final set of included 229 | libs. The `tree` program can provide more info on why or why not a particular 230 | lib is included. 231 | 232 | Licenses will be printed in short form by default but can also be listed as 233 | in :full or :none for none at all using the :license key. 234 | 235 | By default, :format will :print to the console in a human friendly tree. Use 236 | :edn mode to print the tree to edn. 237 | 238 | This program accepts the same basis-modifying arguments from the `basis` program. 239 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 240 | Sources are merged in the order - :root, :user, :project, :extra. 241 | 242 | Options: 243 | :license - :full, :short (default), :none 244 | 245 | Output mode options: 246 | :format :print (default) or :edn 247 | 248 | Basis options: 249 | :dir - directory root path, defaults to current directory 250 | :root - dep source, default = :standard 251 | :user - dep source, default = :standard 252 | :project - dep source, default = :standard (\"./deps.edn\") 253 | :extra - dep source, default = nil 254 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 255 | 256 | The libs are printed to the console." 257 | [params] 258 | (let [{license-mode :license, format :format 259 | :or {license-mode :short, format :print}} params 260 | basis (deps/create-basis params) 261 | libs (:libs basis) 262 | data (into (sorted-map) 263 | (map (fn [lib] 264 | (let [coord (get libs lib) 265 | info (ext/license-info lib coord basis)] 266 | [lib (cond-> coord info (assoc :license info))])) 267 | (-> libs keys sort)))] 268 | (if (= format :edn) 269 | (binding [*print-namespace-maps* false] 270 | (pprint/pprint data)) 271 | (doseq [[lib coord] data] 272 | (let [summary (ext/coord-summary lib coord) 273 | info (:license coord) 274 | license-string (license-string info license-mode)] 275 | (println summary (if license-string (str " (" license-string ")") ""))))))) 276 | 277 | (comment 278 | (list nil) 279 | @license-abbrev 280 | ) 281 | 282 | ;;;; git resolve-tags 283 | 284 | (defn git-resolve-tags 285 | "Resolve git tags in deps.edn git deps to full shas." 286 | [_] 287 | (resolve-tags/exec {:deps-file "deps.edn"})) 288 | 289 | ;;;; Generate pom 290 | 291 | (defn mvn-pom 292 | "Sync or create pom.xml from deps.edn. 293 | 294 | This program accepts the same basis-modifying arguments from the `basis` program. 295 | Each dep source value can be :standard, a string path, a deps edn map, or nil. 296 | Sources are merged in the order - :root, :user, :project, :extra. 297 | 298 | Basis options: 299 | :dir - directory root path, defaults to current directory 300 | :root - dep source, default = :standard 301 | :user - dep source, default = :standard 302 | :project - dep source, default = :standard (\"./deps.edn\") 303 | :extra - dep source, default = nil 304 | :aliases - coll of kw aliases of argmaps to apply to subprocesses 305 | 306 | Deprecated options (use the basis :aliases above instead): 307 | :argmaps - vector of aliases to combine into argmaps to resolve-deps and make-classpath" 308 | [{:keys [argmaps] :as opts}] 309 | (try 310 | (let [opts' (if argmaps (assoc opts :aliases (vec (concat argmaps (:aliases opts)))) opts) 311 | basis (deps/create-basis opts') 312 | ;; treat all transitive deps as top-level deps 313 | updated-deps (reduce-kv (fn [m lib {:keys [dependents] :as coord}] 314 | (if (seq dependents) m (assoc m lib coord))) 315 | {} (:libs basis))] 316 | (gen-pom/sync-pom (merge basis {:deps updated-deps}) (jio/file "."))) 317 | (catch Throwable t 318 | (printerrln "Error generating pom manifest:" (.getMessage t)) 319 | (when-not (instance? IExceptionInfo t) 320 | (.printStackTrace t)) 321 | (System/exit 1)))) 322 | 323 | ;;;; Install jar into local repository 324 | 325 | (defn- read-pom-file 326 | [pom] 327 | (let [pom-file (jio/file pom)] 328 | (if (.exists pom-file) 329 | (let [^Model model (pom/read-model-file pom-file (deps/root-deps))] 330 | {:group-id (.getGroupId model) 331 | :artifact-id (.getArtifactId model) 332 | :version (.getVersion model) 333 | :pom-file pom}) 334 | (throw (FileNotFoundException. (str "Pom file not found: " pom)))))) 335 | 336 | (defn- gen-pom-file 337 | [lib version classifier] 338 | (let [group-id (namespace lib) 339 | artifact-id (name lib) 340 | temp-dir (.toString (Files/createTempDirectory "pom" (make-array FileAttribute 0))) 341 | pom-file (str temp-dir "/pom.xml")] 342 | (gen-pom/sync-pom {:params {:target-dir temp-dir 343 | :src-pom pom-file 344 | :lib lib 345 | :version version}}) 346 | {:group-id group-id 347 | :artifact-id artifact-id 348 | :version version 349 | :classifier classifier 350 | :pom-file pom-file})) 351 | 352 | (defn- read-pom-in-jar 353 | [jar-name] 354 | (let [jar-file (jio/file jar-name)] 355 | (when (or (nil? jar-name) (not (.exists jar-file))) 356 | (throw (FileNotFoundException. (str "Jar file not found: " jar-name)))) 357 | (let [jar (JarFile. jar-file)] 358 | (if-let [path (local/find-pom jar)] 359 | (let [entry (.getJarEntry jar path) 360 | jis (.getInputStream jar entry) 361 | tmp (File/createTempFile "pom" ".xml")] 362 | (jio/copy jis tmp) 363 | (read-pom-file tmp)) 364 | (throw (IOException. (str "Jar file does not contain pom: " jar-name))))))) 365 | 366 | (defn- output-path 367 | [local-repo group-id artifact-id version] 368 | (let [path-parts (concat 369 | [(or local-repo @mvn/cached-local-repo)] 370 | (str/split group-id #"\.") 371 | [artifact-id version])] 372 | (.getAbsolutePath ^File (apply jio/file path-parts)))) 373 | 374 | (defn mvn-install 375 | "Install a jar and pom to the Maven local cache. 376 | The pom file must either be supplied, or generated based 377 | on provided lib/version/classifier, or provided inside the jar. 378 | The group/artifact/version coordinate will be pulled from the 379 | pom source as above. 380 | 381 | Required: 382 | :jar (reqired) - path to jar file (embedded pom used by default) 383 | 384 | Explicit pom options: 385 | :pom - path to pom file (pom in jar ignored) 386 | 387 | Generated pom options: 388 | :lib - qualified symbol like my.org/lib 389 | :version - string 390 | :classifier - string 391 | 392 | Other options: 393 | :local-repo (optional) - path to local repo (default = ~/.m2/repository) 394 | 395 | Execute ad-hoc: 396 | clj -X:deps mvn-install :jar '\"foo-1.2.3.jar\"'" 397 | [{:keys [jar pom lib version classifier local-repo]}] 398 | (println "Installing" jar (if pom (str "and " pom) "")) 399 | (let [{:keys [pom-file group-id artifact-id version classifier]} 400 | (cond 401 | pom (read-pom-file pom) 402 | lib (gen-pom-file lib version classifier) 403 | :else (read-pom-in-jar jar)) 404 | jar-file (jio/file jar) 405 | pom-file (jio/file pom-file) 406 | system (mvn/make-system) 407 | settings (mvn/get-settings) 408 | session (mvn/make-session system settings (or local-repo @mvn/cached-local-repo)) 409 | artifacts [(.setFile (DefaultArtifact. group-id artifact-id classifier "jar" version) jar-file) 410 | (.setFile (DefaultArtifact. group-id artifact-id classifier "pom" version) pom-file)] 411 | install-request (.setArtifacts (InstallRequest.) artifacts)] 412 | (.install system session install-request) 413 | (println "Installed to" (output-path local-repo group-id artifact-id version)))) 414 | 415 | (defn find-versions 416 | "Find available tool versions given either a lib (with :lib) or 417 | existing installed tool (with :tool). If lib, check all registered 418 | procurers and print one coordinate per line when found. 419 | 420 | Options: 421 | :lib Qualified lib symbol 422 | :tool Tool name for installed tool 423 | :n Number of coordinates to return, default = 8, :all for all" 424 | [{:keys [lib tool n] :or {n 8} :as args}] 425 | (let [{:keys [root-edn user-edn]} (deps/find-edn-maps) 426 | master-edn (deps/merge-edns [root-edn user-edn]) 427 | trunc-fn (fn [n x] 428 | (if (= n :all) 429 | x 430 | (mapcat #(take-last n %) (vals (group-by keys x))))) 431 | coords (cond 432 | tool 433 | (if-let [{:keys [lib coord]} (tool/resolve-tool (name tool))] 434 | (ext/find-versions lib coord (ext/coord-type coord) master-edn) 435 | (throw (ex-info (str "Unknown tool: " tool) {:tool tool}))) 436 | 437 | lib 438 | (ext/find-all-versions lib {} master-edn) 439 | 440 | :else 441 | (throw (ex-info "Either :lib or :tool must be provided to find versions" (or args {}))))] 442 | (run! #(binding [*print-namespace-maps* false] (prn %)) (trunc-fn n coords)))) 443 | 444 | (comment 445 | (find-versions '{:lib org.clojure/tools.gitlibs :n 4}) 446 | (find-versions '{:lib io.github.clojure/tools.gitlibs :n 10}) 447 | (find-versions '{:tool tools :n 3}) 448 | (find-versions nil) 449 | ) 450 | --------------------------------------------------------------------------------