Skip to content

Commit 67a223d

Browse files
committed
Add ability to skip dynapath-based functionality
Closes clojure-emacs#112 Related clojure-emacs#103 Related clojure-emacs#105
1 parent 76793ff commit 67a223d

File tree

10 files changed

+160
-96
lines changed

10 files changed

+160
-96
lines changed

.circleci/config.yml

+11-49
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ executors:
2525
docker:
2626
- image: circleci/clojure:openjdk-11-lein-2.9.1
2727
<<: *defaults
28-
openjdk15:
28+
openjdk16:
2929
docker:
30-
- image: circleci/clojure:openjdk-15-lein-2.9.5-buster
30+
- image: circleci/clojure:openjdk-16-lein-2.9.5-buster
3131
<<: *defaults
3232

3333
# Runs a given set of steps, with some standard pre- and post-
@@ -114,9 +114,13 @@ jobs:
114114
clojure_version:
115115
description: Version of Clojure to test against
116116
type: string
117+
test_profiles:
118+
description: Maps directly to the TEST_PROFILES var in Makefile
119+
type: string
117120
executor: << parameters.jdk_version >>
118121
environment:
119122
VERSION: << parameters.clojure_version >>
123+
TEST_PROFILES: << parameters.test_profiles >>
120124
steps:
121125
- checkout
122126
- with_cache:
@@ -146,53 +150,11 @@ workflows:
146150
ci-test-matrix:
147151
jobs:
148152
- test_code:
149-
name: Java 8, Clojure 1.8
150-
clojure_version: "1.8"
151-
jdk_version: openjdk8
152-
- test_code:
153-
name: Java 8, Clojure 1.9
154-
clojure_version: "1.9"
155-
jdk_version: openjdk8
156-
- test_code:
157-
name: Java 8, Clojure 1.10
158-
clojure_version: "1.10"
159-
jdk_version: openjdk8
160-
- test_code:
161-
name: Java 8, Clojure master
162-
clojure_version: "master"
163-
jdk_version: openjdk8
164-
- test_code:
165-
name: Java 11, Clojure 1.8
166-
clojure_version: "1.8"
167-
jdk_version: openjdk11
168-
- test_code:
169-
name: Java 11, Clojure 1.9
170-
clojure_version: "1.9"
171-
jdk_version: openjdk11
172-
- test_code:
173-
name: Java 11, Clojure 1.10
174-
clojure_version: "1.10"
175-
jdk_version: openjdk11
176-
- test_code:
177-
name: Java 11, Clojure master
178-
clojure_version: "master"
179-
jdk_version: openjdk11
180-
- test_code:
181-
name: Java 15, Clojure 1.8
182-
clojure_version: "1.8"
183-
jdk_version: openjdk15
184-
- test_code:
185-
name: Java 15, Clojure 1.9
186-
clojure_version: "1.9"
187-
jdk_version: openjdk15
188-
- test_code:
189-
name: Java 15, Clojure 1.10
190-
clojure_version: "1.10"
191-
jdk_version: openjdk15
192-
- test_code:
193-
name: Java 15, Clojure master
194-
clojure_version: "master"
195-
jdk_version: openjdk15
153+
matrix:
154+
parameters:
155+
jdk_version: [openjdk8, openjdk11, openjdk16]
156+
clojure_version: ["1.8", "1.9", "1.10", "master"]
157+
test_profiles: ["+test", "+test,+no-dynapath"]
196158
- util_job:
197159
name: Code Linting, JDK8 (Eastwood only)
198160
jdk_version: openjdk8

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/checkouts
44
/classes
55
/gh-pages
6+
/unzipped-jdk-source
67
/target
78
autodoc.sh
89
pom.xml

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Changes
1010

11+
* [#113](https://github.com/clojure-emacs/orchard/issues/113) Add ability to skip functionality that works by altering the classpath
12+
* You an opt in to this choice by setting `"-Dorchard.use-dynapath=false"`.
1113
* The _class info cache_ is now initialized silently by default. This results in less confusing output.
1214
* You can now `@orchard.java/cache-initializer` for deterministically waiting for this cache workload to complete.
1315
* You can control its verbosity by setting `"-Dorchard.initialize-cache.silent=false"` (or `[...]=true`).

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
VERSION ?= 1.10
44

5-
TEST_PROFILES := +test
5+
TEST_PROFILES ?= +test
66

77
resources/clojuredocs/export.edn:
88
curl -o $@ https://github.com/clojure-emacs/clojuredocs-export-edn/raw/master/exports/export.compact.edn

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,13 @@ functionality that's provided.
9191
So far, Orchard follows these options, which can be specified as Java system properties
9292
(which means that end users can choose to set them globally without fiddling with tooling internals):
9393

94+
* `"-Dorchard.use-dynapath=false"` (default: true)
95+
* if `false`, all features that currently depend on dynapath (and therefore alter the classpath) will be disabled.
96+
* This is a way to avoid a number of known issues: [#103](https://github.com/clojure-emacs/orchard/issues/103), [#105](https://github.com/clojure-emacs/orchard/issues/105), [#112](https://github.com/clojure-emacs/orchard/pull/112).
97+
* Note that if this option is `false`, Orchard clients will have to figure out themselves a way to e.g. fetch Java sources.
98+
* It is foreseen that soon enough this will be reliably offered as a Lein plugin.
9499
* `"-Dorchard.initialize-cache.silent=true"` (default: `true`)
95-
* if false, the _class info cache_ initialization may print warnings (possibly spurious ones).
100+
* if `false`, the _class info cache_ initialization may print warnings (possibly spurious ones).xx
96101

97102
## History
98103

project.clj

+69-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,61 @@
1+
;;;; The following code allows to add the JDK sources without `dynapath` being present.
2+
3+
(require '[clojure.java.io :as io])
4+
5+
(import '[java.util.zip ZipInputStream]
6+
'[java.io FileOutputStream])
7+
8+
(defmacro while-let [[sym expr] & body]
9+
`(loop [~sym ~expr]
10+
(when ~sym
11+
~@body
12+
(recur ~expr))))
13+
14+
(defn jdk-find [f]
15+
(let [home (io/file (System/getProperty "java.home"))
16+
parent (.getParentFile home)
17+
paths [(io/file home f)
18+
(io/file home "lib" f)
19+
(io/file parent f)
20+
(io/file parent "lib" f)]]
21+
(->> paths (filter #(.canRead ^java.io.File %)) first str)))
22+
23+
(def jdk-sources
24+
(let [java-path->zip-path (fn [path]
25+
(some-> (io/resource path)
26+
^java.net.JarURLConnection (. openConnection)
27+
(. getJarFileURL)
28+
io/as-file
29+
str))]
30+
(or (java-path->zip-path "java.base/java/lang/Object.java") ; JDK9+
31+
(java-path->zip-path "java/lang/Object.java") ; JDK8-
32+
(jdk-find "src.zip"))))
33+
34+
(defn uncompress [path target]
35+
(let [zis (-> target io/input-stream ZipInputStream.)]
36+
(while-let [entry (-> zis .getNextEntry)]
37+
(let [size (-> entry .getSize)
38+
bytes (byte-array 1024)
39+
dest (->> entry .getName (io/file path))
40+
dir (-> entry .getName (clojure.string/split #"/") butlast)
41+
_ (->> (clojure.string/join "/" dir) (java.io.File. path) .mkdirs)
42+
output (FileOutputStream. dest)]
43+
(loop [len (-> zis (.read bytes))]
44+
(when (pos? len)
45+
(-> output (.write bytes 0 len))
46+
(recur (-> zis (.read bytes)))))
47+
(-> output .close)))))
48+
49+
(defn unzipped-jdk-source []
50+
(let [choice jdk-sources]
51+
(when-not (-> "unzipped-jdk-source" io/file .exists)
52+
(-> "unzipped-jdk-source" io/file .mkdirs)
53+
;; For some reason simply adding a .zip to the classpath doesn't work, so one has to uncompress the contents:
54+
(uncompress "./unzipped-jdk-source/" choice))
55+
"unzipped-jdk-source"))
56+
57+
(def jdk8? (->> "java.version" System/getProperty (re-find #"^1.8.")))
58+
159
(defproject cider/orchard "0.6.5"
260
:description "A fertile ground for Clojure tooling"
361
:url "https://github.com/clojure-emacs/orchard"
@@ -23,6 +81,8 @@
2381
:password :env/clojars_password
2482
:sign-releases false}]]
2583

84+
:jvm-opts ["-Dorchard.use-dynapath=true"]
85+
2686
:profiles {
2787
;; Clojure versions matrix
2888
:provided {:dependencies [[org.clojure/clojure "1.10.1"]
@@ -38,10 +98,17 @@
3898
:dependencies [[org.clojure/clojure "1.11.0-master-SNAPSHOT"]
3999
[org.clojure/clojure "1.11.0-master-SNAPSHOT" :classifier "sources"]]}
40100

41-
:test {:resource-paths ["test-resources"]
101+
:test {:dependencies [[org.clojure/java.classpath "1.0.0"]]
102+
:resource-paths ["test-resources"]
42103
;; Initialize the cache verbosely, as usual, so that possible issues can be more easily diagnosed:
43104
:jvm-opts ["-Dorchard.initialize-cache.silent=false"]}
44105

106+
:no-dynapath {:jvm-opts ["-Dorchard.use-dynapath=false"]
107+
:resource-paths [~(unzipped-jdk-source)]
108+
:plugins ~(if jdk8?
109+
'[[lein-jdk-tools "0.1.1"]]
110+
[])}
111+
45112
;; Development tools
46113
:dev {:dependencies [[pjstadig/humane-test-output "0.10.0"]]
47114
:resource-paths ["test-resources"]
@@ -63,8 +130,6 @@
63130
{:dependencies [[clj-kondo "2021.03.31"]]}]
64131

65132
:eastwood {:plugins [[jonase/eastwood "0.4.0"]]
66-
:eastwood {:exclude-namespaces [~(if (-> "java.version"
67-
System/getProperty
68-
(.contains "1.8."))
133+
:eastwood {:exclude-namespaces [~(if jdk8?
69134
'orchard.java.parser
70135
'orchard.java.legacy-parser)]}}})

src/orchard/java.clj

+20-11
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,24 @@
5858
(io/file parent "lib" f)]]
5959
(->> paths (filter #(.canRead ^File %)) first io/as-url)))
6060

61+
(def add-java-sources-via-dynapath?
62+
"Should orchard use the dynapath library to use \"fetch Java sources\" functionality?
63+
64+
Note that using dynapath currently implies some bugs, so you might want to disable this option."
65+
(contains? #{"true" "1"} (System/getProperty "orchard.use-dynapath" "true")))
66+
6167
(def jdk-sources
6268
"The JDK sources path. If found on the existing classpath, this is the
6369
corresponding classpath entry. Otherwise, the JDK directory is searched for
6470
the file `src.zip`."
65-
(let [base-url (fn [path]
66-
(some-> (io/resource path)
67-
^JarURLConnection (. openConnection)
68-
(. getJarFileURL)))]
69-
(or (base-url "java.base/java/lang/Object.java") ; JDK9+
70-
(base-url "java/lang/Object.java") ; JDK8-
71-
(jdk-find "src.zip"))))
71+
(when add-java-sources-via-dynapath?
72+
(let [base-url (fn [path]
73+
(some-> (io/resource path)
74+
^JarURLConnection (. openConnection)
75+
(. getJarFileURL)))]
76+
(or (base-url "java.base/java/lang/Object.java") ; JDK9+
77+
(base-url "java/lang/Object.java") ; JDK8-
78+
(jdk-find "src.zip")))))
7279

7380
(def jdk-tools
7481
"The `tools.jar` path, for JDK8 and earlier. If found on the existing
@@ -78,15 +85,17 @@
7885
(or (some-> (io/resource "com/sun/javadoc/Doc.class")
7986
^JarURLConnection (. openConnection)
8087
(. getJarFileURL))
81-
(some-> (jdk-find "tools.jar") cp/add-classpath!))))
88+
(and add-java-sources-via-dynapath?
89+
(some-> (jdk-find "tools.jar") cp/add-classpath!)))))
8290

8391
(defn ensure-jdk-sources
8492
"If `jdk-sources` is present, check that this entry is on the context
8593
classpath and if not, add it."
8694
[]
87-
(let [classpath (set (cp/classpath))]
88-
(when (and jdk-sources (not (classpath jdk-sources)))
89-
(cp/add-classpath! jdk-sources))))
95+
(when add-java-sources-via-dynapath?
96+
(let [classpath (set (cp/classpath))]
97+
(when (and jdk-sources (not (classpath jdk-sources)))
98+
(cp/add-classpath! jdk-sources)))))
9099

91100
;;; ## Javadoc URLs
92101
;;

test/orchard/java/classpath_test.clj

+30-27
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
[clojure.set :as set]
55
[clojure.string :as str]
66
[clojure.test :refer [deftest is testing]]
7+
[orchard.java]
78
[orchard.java.classpath :as cp]
89
[orchard.misc :as misc])
910
(:import
@@ -48,31 +49,33 @@
4849
(set (cp/system-classpath))
4950
(set (cp/classpath)))))))
5051

51-
(deftest classpath-resources-test
52-
(testing "Iterating classpath resources"
53-
(testing "returns non-empty lists"
54-
(is (every? seq (map cp/classpath-seq (cp/classpath)))))
55-
(testing "returns relative paths"
56-
(is (every? #(not (.isAbsolute (File. %)))
57-
(mapcat cp/classpath-seq (cp/classpath)))))))
52+
(when orchard.java/add-java-sources-via-dynapath?
53+
(deftest classpath-resources-test
54+
(testing "Iterating classpath resources"
55+
(testing "returns non-empty lists"
56+
(is (every? seq (map cp/classpath-seq (cp/classpath)))))
57+
(testing "returns relative paths"
58+
(is (every? #(not (.isAbsolute (File. %)))
59+
(mapcat cp/classpath-seq (cp/classpath))))))))
5860

59-
(deftest classloader-test
60-
(testing "Classloader hierarchy contains current classloader"
61-
(is (contains? (set (cp/classloaders)) (cp/context-classloader))))
62-
(testing "Classpath modification"
63-
(let [orig-classloaders (cp/classloaders)
64-
orig-classpath (cp/classpath)
65-
url (-> (System/getProperty "java.io.tmpdir")
66-
(io/file "test.txt")
67-
(io/as-url))]
68-
(cp/add-classpath! url)
69-
(testing "adds the URL"
70-
(is (contains? (set (cp/classpath)) url)))
71-
(testing "preserves prior classpath URLs"
72-
(is (set/subset?
73-
(set orig-classpath)
74-
(set (cp/classpath)))))
75-
(testing "preserves the classloader hierarchy"
76-
(is (set/subset?
77-
(set orig-classloaders)
78-
(set (cp/classloaders))))))))
61+
(when orchard.java/add-java-sources-via-dynapath?
62+
(deftest classloader-test
63+
(testing "Classloader hierarchy contains current classloader"
64+
(is (contains? (set (cp/classloaders)) (cp/context-classloader))))
65+
(testing "Classpath modification"
66+
(let [orig-classloaders (cp/classloaders)
67+
orig-classpath (cp/classpath)
68+
url (-> (System/getProperty "java.io.tmpdir")
69+
(io/file "test.txt")
70+
(io/as-url))]
71+
(cp/add-classpath! url)
72+
(testing "adds the URL"
73+
(is (contains? (set (cp/classpath)) url)))
74+
(testing "preserves prior classpath URLs"
75+
(is (set/subset?
76+
(set orig-classpath)
77+
(set (cp/classpath)))))
78+
(testing "preserves the classloader hierarchy"
79+
(is (set/subset?
80+
(set orig-classloaders)
81+
(set (cp/classloaders)))))))))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns orchard.java.classpath-test.third-party-compat-test
2+
(:require
3+
[orchard.java]
4+
[clojure.java.classpath]
5+
[clojure.test :refer [deftest is]]))
6+
7+
;; make this namespace's tests deterministic:
8+
@orchard.java/cache-initializer
9+
10+
(when-not orchard.java/add-java-sources-via-dynapath?
11+
(deftest works
12+
(is (seq (clojure.java.classpath/classpath-directories))
13+
"The presence of `clojure.java` does not affect third-party libraries")))

test/orchard/java_test.clj

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99

1010
(def jdk-parser? (or (>= misc/java-api-version 9) jdk-tools))
1111

12-
(when-not jdk-parser? (println "No JDK parser available!"))
13-
(when-not jdk-sources (println "No JDK sources available!"))
12+
(assert jdk-parser? "No JDK parser available!")
13+
(assert (if orchard.java/add-java-sources-via-dynapath?
14+
jdk-sources
15+
true)
16+
"No JDK sources available!")
1417

1518
(javadoc/add-remote-javadoc "com.amazonaws." "http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/")
1619
(javadoc/add-remote-javadoc "org.apache.kafka." "https://kafka.apache.org/090/javadoc/")
@@ -25,7 +28,8 @@
2528
(dp/all-classpath-urls)
2629
(set))]
2730
(testing "of defined vars"
28-
(is (= jdk-sources jdk-sources-path))
31+
(when orchard.java/add-java-sources-via-dynapath?
32+
(is (= jdk-sources jdk-sources-path)))
2933
(is (= jdk-tools jdk-tools-path)))
3034
(testing "of dynamically added classpath entries"
3135
(is (= jdk-sources (classpath-urls jdk-sources)))

0 commit comments

Comments
 (0)