From b23ca16d33bd7a9dc8d4a567936b25171cccbf77 Mon Sep 17 00:00:00 2001 From: vemv Date: Fri, 14 Jan 2022 20:32:19 +0100 Subject: [PATCH] Implement a `clojure` wrapper Fixes https://github.com/clojure-emacs/enrich-classpath/issues/2 Closes https://github.com/clojure-emacs/enrich-classpath/pull/8 --- .github/workflows/pr.yml | 6 +- Makefile | 1 + project.clj | 17 ++- sample.deps.edn | 6 + src/cider/enrich_classpath/clojure.clj | 128 ++++++++++++++++++ src/cider/enrich_classpath/clojure.sh | 40 ++++++ .../cider/enrich_classpath/clojure.clj | 19 +++ 7 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 sample.deps.edn create mode 100644 src/cider/enrich_classpath/clojure.clj create mode 100755 src/cider/enrich_classpath/clojure.sh create mode 100644 test/integration/cider/enrich_classpath/clojure.clj diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5ab1cdd..4d34efe 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -14,7 +14,7 @@ jobs: os: ["ubuntu-18.04", "macOS-latest"] lein-version: ["2.8.1", "2.9.4"] java-version: ["8", "11", "16"] - integration-test-parallelism: ["1", "4"] + integration-test-parallelism: ["1"] steps: - name: m2 cache uses: actions/cache@v2 @@ -32,9 +32,9 @@ jobs: distribution: 'adopt' java-version: ${{ matrix.java-version }} - run: java -version - - uses: DeLaGuardo/setup-clojure@91054c3b9dc15fdc6a2f45be47405d891e672ef0 + - uses: DeLaGuardo/setup-clojure@fa522696baadfef7de0fe810135f446221e665c2 with: - cli: '1.10.1.469' + cli: '1.10.3.1058' lein: ${{ matrix.lein-version }} # should match with `#'integration-test/lein`: - run: which lein diff --git a/Makefile b/Makefile index 94e2d6d..16dd417 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ clean: lein clean rm -f .inline-deps + rm -rf .cpcache .inline-deps: clean lein with-profile -user inline-deps diff --git a/project.clj b/project.clj index 93d9d69..22ddbf9 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject mx.cider/enrich-classpath "1.6.2" +(defproject mx.cider/enrich-classpath "1.7.0" :description "Makes available .jars with Java sources and javadocs for a given project." :url "https://github.com/clojure-emacs/enrich-classpath" @@ -6,12 +6,15 @@ :license {:name "EPL-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} - :dependencies [[org.clojure/clojure "1.10.3"] ;; Hard-require a recent-enough version of Clojure, since other plugins may require an overly old one which would make Fipp fail. - ^:inline-dep [fipp "0.6.25" :exclusions [org.clojure/clojure]]] + :dependencies [;; lein assumes it but t.deps requires it: + [clj-commons/pomegranate "1.2.1"] + ^:inline-dep [fipp "0.6.25" :exclusions [org.clojure/clojure]] + [org.clojure/clojure "1.10.3"] ;; Hard-require a recent-enough version of Clojure, since other plugins may require an overly old one which would make Fipp fail. + [org.clojure/tools.deps.alpha "0.12.1109"]] :eval-in-leiningen ~(nil? (System/getenv "no_eval_in_leiningen")) - :plugins [[thomasa/mranderson "0.5.4-SNAPSHOT"]] + :plugins [[thomasa/mranderson "0.5.3"]] :mranderson {:project-prefix "cider.enrich-classpath.inlined-deps" :expositions [] @@ -22,11 +25,7 @@ :password :env/clojars_password :sign-releases false}]] - :profiles {;; Helps developing the plugin when (false? eval-in-leiningen): - :test {:dependencies [[clj-commons/pomegranate "1.2.0"] - [org.clojure/clojure "1.10.3"]]} - - :integration-testing {:source-paths ["integration-testing"]} + :profiles {:integration-testing {:source-paths ["integration-testing"]} :self-test {:middleware [cider.enrich-classpath/middleware] ;; ensure that at least one dependency will fetch sources: diff --git a/sample.deps.edn b/sample.deps.edn new file mode 100644 index 0000000..62b0111 --- /dev/null +++ b/sample.deps.edn @@ -0,0 +1,6 @@ +{:paths ["src" "test" "resource" "resources" "other"] + :aliases {:some-alias {:extra-paths ["the-extra-path"] + :extra-deps {refactor-nrepl/refactor-nrepl {:mvn/version "3.2.0"}}}} + :deps {org.clojure/clojure {:mvn/version "1.10.3"} + org.clojars.brenton/google-diff-match-patch {:mvn/version "0.1"} + org.ow2.asm/asm-all {:mvn/version "5.2"}}} diff --git a/src/cider/enrich_classpath/clojure.clj b/src/cider/enrich_classpath/clojure.clj new file mode 100644 index 0000000..b0a9a40 --- /dev/null +++ b/src/cider/enrich_classpath/clojure.clj @@ -0,0 +1,128 @@ +(ns cider.enrich-classpath.clojure + (:require + [cider.enrich-classpath :as enrich-classpath] + [clojure.java.io :as io] + [clojure.string :as string] + [clojure.tools.deps.alpha :as tools.deps]) + (:import + (java.io File))) + +(defn commandize [args clojure] + (->> args + (apply vector clojure) + (string/join " "))) + +(defn impl ^String [clojure deps-edn-filename pwd args] + {:pre [(vector? args)]} ;; for conj + (let [aliases (into #{} + (comp (mapcat (fn [^String s] + (when (-> s (.startsWith "-A")) + (-> s + (string/replace #"-A:" "") + (string/replace #"-A" "") + (string/split #":"))))) + (map keyword)) + args) + {:keys [paths deps] + {:keys [extra-paths extra-deps]} :classpath-args + :as basis} (tools.deps/create-basis {:project (-> pwd (io/file deps-edn-filename) str) + :aliases aliases}) + paths (into paths extra-paths) + deps (into deps extra-deps) + original-paths-set (set paths) + original-deps-set (->> deps (map first) set) + {:keys [dependencies + resource-paths]} (enrich-classpath/middleware {:dependencies (->> deps + (map (fn [[artifact-name {mv :mvn/version}]] + [artifact-name mv])) + (into {})) + ;; XXX + ;; :repositories repositories + ;; :managed-dependencies managed-dependencies + :resource-paths paths}) + {:keys [classpath]} (tools.deps/calc-basis {:paths paths + :deps (->> dependencies + (map (fn [[k v marker classifier]] + [(cond-> k + (#{:classifier} marker) + (str "$" classifier) + + true symbol) + {:mvn/version v}])) + (into {}))}) + ;; Avoids + ;; `WARNING: Use of :paths external to the project has been deprecated, please remove: ...`: + classpath (->> resource-paths + (remove original-paths-set) + (map (fn [entry] + {entry {:path-key ::_}})) + (into classpath)) + classpath (->> classpath + (sort-by (fn [[^String entry {:keys [lib-name path-key]}]] + {:pre [(or lib-name path-key)]} + (let [original-path? (and path-key (original-paths-set entry))] + (cond + (and original-path? + (-> entry (.contains "src"))) + (str "0" entry) + + (and original-path? + (-> entry (.contains "test"))) + (str "1" entry) + + (and original-path? + (-> entry (.contains "resource"))) + (str "3" entry) + + original-path? + (str "2" entry) + + ;; Let the original Clojure .clj libs go before any other deps - + ;; makes it less likely for other libs to overwrite Clojure stuff: + (and lib-name + (-> entry (.contains "/org/clojure/")) + (not (-> lib-name str (.contains "$")))) + (str "4" lib-name) + + (original-deps-set lib-name) + (str "5" lib-name) + + (and lib-name + (not (-> lib-name str (.contains "$")))) + (str "6" lib-name) + + (and path-key + (-> entry (.contains "unzipped-jdk-sources"))) + (str "10" entry) + + path-key ;; JDK sources + (str "7" entry) + + lib-name ;; artifacts with sources or javadocs + (str "8" lib-name) + + true ;; shouldn't happen, anyway we leave something reasonable + (str "9" (or lib-name path-key)))))) + (map first) + (string/join File/pathSeparator))] + (-> args + (conj "-Sforce" "-Srepro" "-J-XX:-OmitStackTraceInFastThrow" "-J-Dclojure.main.report=stderr" "-Scp" classpath) + (commandize clojure)))) + +(defn -main [clojure pwd & args] + (println (try + (impl clojure "deps.edn" pwd (vec args)) + (catch AssertionError e + (-> e .printStackTrace) + (commandize args clojure)) + (catch Exception e + (-> e .printStackTrace) + (commandize args clojure)))) + (shutdown-agents) + (System/exit 0)) + +(comment + (impl "clojure" + "deps.edn" + (System/getProperty "user.dir") + ["-Asome-alias"])) diff --git a/src/cider/enrich_classpath/clojure.sh b/src/cider/enrich_classpath/clojure.sh new file mode 100755 index 0000000..3e99ecd --- /dev/null +++ b/src/cider/enrich_classpath/clojure.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -Eeuxo pipefail + +clojure="$1" +# remove it from "$@"/"$*": +shift + +file="deps.edn" + +if [ ! -e $file ]; then + echo "$file not found." + $clojure "$@" +elif [[ "$*" == *Spath* ]]; then + echo "-Spath passed; skipping enrich-classpath." + $clojure "$@" +elif [[ "$*" == *Scp* ]]; then + echo "-Scp passed; skipping enrich-classpath." + $clojure "$@" +else + + here="$PWD" + + # don't let local deps.edn files interfere: + cd + + output=$("$clojure" -Sforce -Srepro -J-XX:-OmitStackTraceInFastThrow -J-Dclojure.main.report=stderr -Sdeps '{:deps {mx.cider/enrich-classpath {:mvn/version "1.7.0"}}}' -M -m cider.enrich-classpath.clojure "$clojure" "$here" "$@") + cmd=$(tail -n1 <(echo "$output")) + + cd "$here" + + if grep --silent "^$clojure" <<< "$cmd"; then + $cmd + else + # Print errors: + echo "$output" + $clojure "$@" + fi + # (System/getProperty "java.class.path") + +fi diff --git a/test/integration/cider/enrich_classpath/clojure.clj b/test/integration/cider/enrich_classpath/clojure.clj new file mode 100644 index 0000000..5114706 --- /dev/null +++ b/test/integration/cider/enrich_classpath/clojure.clj @@ -0,0 +1,19 @@ +(ns integration.cider.enrich-classpath.clojure + (:require + [cider.enrich-classpath.clojure :as sut] + [clojure.test :refer [deftest is testing]])) + +(deftest works + (testing "Returns a valid command with an -Scp specifying an enriched classpath, carefully sorted, and honoring aliases" + (let [actual (sut/impl "clojure" "sample.deps.edn" + (System/getProperty "user.dir") + ["-Asome-alias"])] + (is (-> actual (.contains "src:test:other:the-extra-path:resource:resources"))) + (is (-> actual (.contains "the-extra-path"))) + (is (-> actual (.contains "refactor-nrepl"))) + (is (-> actual (.contains "-Scp"))) + (is (-> actual (.contains "src.zip"))) + (is (-> actual (.contains "-sources.jar"))) + (is (-> actual (.contains "-javadoc.jar"))) + (when (re-find #"^1\.8\." (System/getProperty "java.version")) + (is (-> actual (.contains "unzipped-jdk-sources")))))))