diff --git a/.build/bb.edn b/.build/bb.edn
index 6ec32294..125c9cc5 100644
--- a/.build/bb.edn
+++ b/.build/bb.edn
@@ -2,5 +2,5 @@
:deps {borkdude/gh-release-artifact
#_{:local/root "../gh-release-artifact"}
{:git/url "https://github.com/borkdude/gh-release-artifact"
- :git/sha "ce060c12a25b552b864dc90f8fb344a2eb91ea9d"}}
+ :git/sha "4a9a74f0e50e897c45df8cc70684360eb30fce80"}}
:tasks {release-artifact babashka.release-artifact/release}}
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3e0293e5..4434ec9e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -29,7 +29,7 @@ jobs:
- run:
name: Generate config
command: |
- /tmp/bbb .circleci/script/short_ci.clj > generated_config.yml
+ /tmp/bbb .circleci/script/gen_ci.clj > generated_config.yml
- continuation/continue:
configuration_path: generated_config.yml
diff --git a/.circleci/script/docker.clj b/.circleci/script/docker.clj
index a884c893..a64ee3f5 100644
--- a/.circleci/script/docker.clj
+++ b/.circleci/script/docker.clj
@@ -1,6 +1,6 @@
-(require '[clojure.string :as str]
+(require '[babashka.fs :as fs]
'[babashka.process :as proc]
- '[babashka.fs :as fs])
+ '[clojure.string :as str])
(import '[java.time Instant])
(defn read-env
@@ -12,7 +12,9 @@
(def image-name "babashka/babashka")
-(def image-tag (slurp "resources/BABASHKA_VERSION"))
+(def ghcr-image-name "ghcr.io/babashka/babashka")
+
+(def image-tag (str/trim (slurp "resources/BABASHKA_VERSION")))
(def latest-tag "latest")
@@ -46,6 +48,11 @@
[username password]
(exec ["docker" "login" "-u" username "-p" password]))
+(defn docker-login-ghcr
+ [username password]
+ (exec ["docker" "login" "ghcr.io" "-u" username "-p" password]))
+
+;; TODO: Remove this when Dockerhub goes off
(defn build-push
[image-tag platform docker-file]
(println (format "Building and pushing %s Docker image(s) %s:%s"
@@ -59,12 +66,25 @@
"-f" docker-file]]
(exec (concat base-cmd label-args ["."]))))
+(defn build-push-ghcr
+ [image-tag platform docker-file]
+ (println (format "Building and pushing %s Docker image(s) %s:%s to GHCR"
+ platform
+ ghcr-image-name
+ image-tag))
+ (let [base-cmd ["docker" "buildx" "build"
+ "-t" (str ghcr-image-name ":" image-tag)
+ "--platform" platform
+ "--push"
+ "-f" docker-file]]
+ (exec (concat base-cmd label-args ["."]))))
+
(defn build-push-images
[]
(doseq [platform (str/split platforms #",")]
(let [tarball-platform (str/replace platform #"\/" "-")
tarball-platform (if (= "linux-arm64" tarball-platform)
- "linux-aarch64"
+ "linux-aarch64-static"
tarball-platform)
tarball-path (format "/tmp/release/babashka-%s-%s.tar.gz"
image-tag
@@ -74,16 +94,20 @@
; this overwrites, but this is to work around having built the uberjar/metabom multiple times
(fs/copy (format "/tmp/release/%s-metabom.jar" tarball-platform) "metabom.jar" {:replace-existing true})))
(build-push image-tag platforms "Dockerfile.ci")
+ (build-push-ghcr image-tag platforms "Dockerfile.ci")
(when-not snapshot?
- (build-push latest-tag platforms "Dockerfile.ci")))
+ (build-push latest-tag platforms "Dockerfile.ci")
+ (build-push-ghcr latest-tag platforms "Dockerfile.ci")))
(defn build-push-alpine-images
"Build alpine image for linux-amd64 only (no upstream arm64 support yet)"
[]
(exec ["tar" "zxvf" (str "/tmp/release/babashka-" image-tag "-linux-amd64-static.tar.gz")])
(build-push (str image-tag "-alpine") "linux/amd64" "Dockerfile.alpine")
+ (build-push-ghcr (str image-tag "-alpine") "linux/amd64" "Dockerfile.alpine")
(when-not snapshot?
- (build-push "alpine" "linux/amd64" "Dockerfile.alpine")))
+ (build-push "alpine" "linux/amd64" "Dockerfile.alpine")
+ (build-push-ghcr "alpine" "linux/amd64" "Dockerfile.alpine")))
(when (= *file* (System/getProperty "babashka.file"))
(if (and (nil? (read-env "CIRCLE_PULL_REQUEST"))
@@ -93,6 +117,7 @@
(println "This is a snapshot version")
(println "This is a non-snapshot version"))
(docker-login (read-env "DOCKERHUB_USER") (read-env "DOCKERHUB_PASS"))
+ (docker-login-ghcr (read-env "CONTAINER_REGISTRY_USER") (read-env "BB_GHCR_TOKEN"))
(build-push-images)
(build-push-alpine-images))
(println "Not publishing docker image(s).")))
diff --git a/.circleci/script/short_ci.clj b/.circleci/script/gen_ci.clj
similarity index 89%
rename from .circleci/script/short_ci.clj
rename to .circleci/script/gen_ci.clj
index f467f36b..7fadc293 100644
--- a/.circleci/script/short_ci.clj
+++ b/.circleci/script/gen_ci.clj
@@ -1,10 +1,12 @@
-(ns short-ci
+(ns gen-ci
(:require
[babashka.tasks :as tasks]
[clj-yaml.core :as yaml]
[clojure.string :as str]
[flatland.ordered.map :refer [ordered-map]]))
+(def graalvm-version "22")
+
(defn run
([cmd-name cmd]
(run cmd-name cmd nil))
@@ -80,8 +82,9 @@
:working_directory "~/repo"
:environment {:LEIN_ROOT "true"
:BABASHKA_PLATFORM "linux"
- :GRAALVM_VERSION "22.3.0"
- :GRAALVM_HOME graalvm-home}
+ :GRAALVM_VERSION graalvm-version
+ :GRAALVM_HOME graalvm-home
+ :BABASHKA_TEST_ENV "jvm"}
:resource_class "large"
:steps
(gen-steps
@@ -119,7 +122,7 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
(defn unix
[shorted? static? musl? arch executor-conf resource-class graalvm-home platform]
(let [env {:LEIN_ROOT "true"
- :GRAALVM_VERSION "22.3.0"
+ :GRAALVM_VERSION graalvm-version
:GRAALVM_HOME graalvm-home
:BABASHKA_PLATFORM (if (= "mac" platform)
"macos"
@@ -154,6 +157,8 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
:steps (gen-steps shorted?
(filter some?
[:checkout
+ (when (contains? #{"linux" "linux-aarch64"} platform)
+ (run "Check max glibc version" "script/check_glibc.sh"))
{:attach_workspace {:at "/tmp"}}
(run "Pull Submodules" "git submodule init\ngit submodule update")
{:restore_cache
@@ -167,13 +172,16 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
(str base-install-cmd "\nsudo -E script/setup-musl")
base-install-cmd)))
(run "Download GraalVM" "script/install-graalvm")
- (run "Build binary" "script/uberjar\nscript/compile" "30m")
+ #_(run "Download iprof" "curl -sLO 'https://github.com/babashka/pgo-profiles/releases/download/2023.10.11/default.iprof'")
+ (run "Build binary" (if (= "aarch64" arch)
+ "script/uberjar\nscript/compile -H:PageSize=64K # --pgo=default.iprof"
+ "script/uberjar\nscript/compile # --pgo=default.iprof") "30m")
(run "Run tests" "script/test\nscript/run_lib_tests")
(run "Release" ".circleci/script/release")
{:persist_to_workspace {:root "/tmp"
:paths ["release"]}}
{:save_cache
- {:paths ["~/.m2" "~/graalvm-ce-java11-22.3.0"]
+ {:paths ["~/.m2" "~/graalvm"]
:key cache-key}}
{:store_artifacts {:path "/tmp/release"
:destination "release"}}
@@ -184,9 +192,9 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
[shorted?]
(let [docker-executor-conf {:docker [{:image "circleci/clojure:openjdk-11-lein-2.9.8-bullseye"}]}
machine-executor-conf {:machine {:image "ubuntu-2004:202111-01"}}
- mac-executor-conf {:macos {:xcode "14.0.0"}}
- linux-graalvm-home "/home/circleci/graalvm-ce-java11-22.3.0"
- mac-graalvm-home "/Users/distiller/graalvm-ce-java11-22.3.0/Contents/Home"]
+ mac-executor-conf {:macos {:xcode "12.5.1"}}
+ linux-graalvm-home (str "/home/circleci/graalvm-" graalvm-version)
+ mac-graalvm-home (format "/Users/distiller/graalvm-%s/Contents/Home" graalvm-version)]
(ordered-map
:version 2.1
:commands
@@ -201,17 +209,9 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
:linux (unix shorted? false false "amd64" docker-executor-conf "large" linux-graalvm-home "linux")
:linux-static
(unix shorted? true true "amd64" docker-executor-conf "large" linux-graalvm-home "linux")
- :linux-aarch64 (unix shorted?
- false
- false
- "aarch64"
- machine-executor-conf
- "arm.large"
- linux-graalvm-home
- "linux")
:linux-aarch64-static
(unix shorted? true false "aarch64" machine-executor-conf "arm.large" linux-graalvm-home "linux")
- :mac (unix shorted? false false "amd64" mac-executor-conf "large" mac-graalvm-home "mac")
+ :mac (unix shorted? false false "amd64" mac-executor-conf "macos.x86.medium.gen2" mac-graalvm-home "mac")
:deploy (deploy shorted?)
:docker (docker shorted?))
:workflows (ordered-map
@@ -220,12 +220,11 @@ java -jar \"$jar\" --config .build/bb.edn --deps-root . release-artifact \"$refl
"linux"
"linux-static"
"mac"
- "linux-aarch64"
"linux-aarch64-static"
{:deploy {:filters {:branches {:only "master"}}
:requires ["jvm" "linux"]}}
{:docker {:filters {:branches {:only "master"}}
- :requires ["linux" "linux-static" "linux-aarch64"]}}]}))))
+ :requires ["linux" "linux-static" "linux-aarch64-static"]}}]}))))
(def skip-config
{:skip-if-only [#".*.md$"
diff --git a/.cirrus.yml b/.cirrus.yml
index 34ebcced..270c6925 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -5,8 +5,8 @@ task:
skip: "changesIncludeOnly('logo/*', '**.md')"
env:
LEIN_ROOT: "true"
- GRAALVM_VERSION: "22.3.0"
- GRAALVM_HOME: ${HOME}/graalvm-ce-java11-22.3.0/Contents/Home
+ GRAALVM_VERSION: "22"
+ GRAALVM_HOME: ${HOME}/graalvm-${GRAALVM_VERSION}/Contents/Home
BABASHKA_PLATFORM: macos # used in release script
BABASHKA_ARCH: aarch64
BABASHKA_TEST_ENV: native
@@ -25,7 +25,8 @@ task:
java -version
script/uberjar
- script/compile
+ # curl -sLO 'https://github.com/babashka/pgo-profiles/releases/download/2023.10.11/default.iprof'
+ script/compile # --pgo=default.iprof
# script/test
# script/run_lib_tests
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 66e1f6ef..5f35f824 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -43,7 +43,7 @@ jobs:
uses: actions/setup-java@v2
with:
distribution: 'adopt-hotspot'
- java-version: '11'
+ java-version: '19'
- name: Install clojure tools
uses: DeLaGuardo/setup-clojure@5.0
@@ -102,7 +102,7 @@ jobs:
runs-on: ${{ matrix.os }}
env:
LEIN_ROOT: "true"
- GRAALVM_VERSION: "22.3.0"
+ GRAALVM_VERSION: "22"
BABASHKA_PLATFORM: ${{ matrix.name }} # used in release script
BABASHKA_TEST_ENV: native
BABASHKA_XMX: "-J-Xmx6500m"
@@ -126,8 +126,8 @@ jobs:
if: "matrix.static == false"
uses: graalvm/setup-graalvm@v1
with:
- version: '22.3.0'
- java-version: '11'
+ java-version: '22'
+ distribution: 'graalvm'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -135,8 +135,8 @@ jobs:
if: "matrix.static == true"
uses: graalvm/setup-graalvm@v1
with:
- version: '22.3.0'
- java-version: '11'
+ version: '22'
+ distribution: 'graalvm'
components: 'native-image'
native-image-musl: true
github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 284c61e2..b5cf81da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,5 @@ bb.build_artifacts.txt
target
.nrepl-port
.DS_Store
+.portal
+default.iprof
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 473540ad..db2c54f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,252 @@ A preview of the next release can be installed from
## Unreleased
+- Fix [#1688](https://github.com/babashka/babashka/issues/1688): use-fixtures should add metadata to `*ns*`
+- Fix [#1692](https://github.com/babashka/babashka/issues/1692): Add support for ITransientSet and org.flatland/ordered-set
+- Bump org.flatland/ordered to `1.15.12`.
+
+## 1.3.190 (2024-04-17)
+
+- Fix [#1679](https://github.com/babashka/babashka/issues/1679): bump timbre and fix wrapping `timbre/log!`
+- Add `java.util.concurrent.CountDownLatch`
+- Add `java.lang.ThreadLocal`
+- Bump `babashka.process`
+- Bump httpkit to `2.8.0-RC1`
+- Bump clojure to `1.11.2`
+- Bump deps.clj
+- Bump `babashka.cli`
+- Bump `cheshire` to `5.13.0`
+- Bump `http-client` to `0.4.17`
+
+## 1.3.189 (2024-02-22)
+
+- [#1660](https://github.com/babashka/babashka/issues/1660): add `:deps-root` as part of hash to avoid caching issue with `deps.clj`
+- [#1632](https://github.com/babashka/babashka/issues/1632): fix `(.readPassword (System/console))` by upgrading GraalVM to `21.0.2`
+- [#1661](https://github.com/babashka/babashka/issues/1661): follow symlink when reading adjacent bb.edn
+- [#1665](https://github.com/babashka/babashka/issues/1665): `read-string` should use non-indexing reader for compatibilty with Clojure
+- Bump edamame to 1.4.24
+- Bump http-client to 0.4.16
+- Bump babashka.cli to 0.8.57
+- Uberjar task: support reader conditional in .cljc file
+- Support reader conditional in .cljc file when creating uberjar
+- Add more `javax.net.ssl` classes
+- [#1675](https://github.com/babashka/babashka/issues/1675): add `hash-unordered-coll`
+
+## 1.3.188 (2024-01-12)
+
+- [#1658](https://github.com/babashka/babashka/issues/1658): fix command line parsing for scripts that parse `--version` or `version` etc
+
+## 1.3.187 (2024-01-09)
+
+- Add `clojure.reflect/reflect`
+- Add `java.util.ScheduledFuture`, `java.time.temporal.WeekFields`
+- Support `Runnable` to be used without import
+- Allow `catch` to be used as var name
+- [#1646](https://github.com/babashka/babashka/issues/1646): command-line-args are dropped when file exists with same name
+- [#1645](https://github.com/babashka/babashka/issues/1645): Support for `clojure.lang.LongRange`
+- [#1652](https://github.com/babashka/babashka/issues/1652): allow `bb.edn` to be empty
+- [#1586](https://github.com/babashka/babashka/issues/1586): warn when config file doesn't exist and `--debug` is enabled
+- [#1410](https://github.com/babashka/babashka/issues/1410): better error message when exec fn doesn't exist
+- Bump `babashka.cli` to `0.8.55` which contains subcommand improvements
+- Bump `deps.clj` to `1.11.1.1435`
+- Bump `babashka.fs` to `0.5.20`
+- Compatibility with `plumbing.core`
+- Compatibility with `shadow.css` by improving `tools.reader` compatibility
+- [#1647](https://github.com/babashka/babashka/issues/1647): Allow capturing env vars at build time (only relevant for building bb)
+
+## 1.3.186 (2023-11-02)
+
+- [Support self-contained binaries as uberjars!](https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar)
+- Add `java.security.KeyFactory`, `java.security.spec.PKCS8EncodedKeySpec`, `java.net.URISyntaxException`, `javax.crypto.spec.IvParameterSpec`
+- Fix babashka.process/exec wrt `babashka.process/*defaults*`
+- [#1632](https://github.com/babashka/babashka/issues/1632): Partial fix for `(.readPassword (System/console))`
+- Enable producing self-contained binaries using [uberjars](https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar)
+- Bump httpkit to `2.8.0-beta3` (fixes GraalVM issue with virtual threads)
+- Bump `deps.clj` and `fs`
+- Expose `taoensso.timbre.appenders.core`
+- nREPL: implement `ns-list` op
+- SCI: optimize `swap!`, `deref` and `reset!` for normal atoms (rather than user-created `IAtom`s)
+- Add test for [#1639](https://github.com/babashka/babashka/issues/1639)
+- Upgrade to GraalVM 21.0.1
+
+## 1.3.185 (2023-09-28)
+
+- [#1624](https://github.com/babashka/babashka/pull/1624): Use Oracle GraalVM 21 ([@lispyclouds](https://github.com/lispyclouds))
+- Use PGO to speed up loops (now 2-3x faster for `(time (loop [val 0 cnt 10000000] (if (pos? cnt) (recur (inc val) (dec cnt)) val)))`!)
+- Bump babashka.http-client to v0.4.15
+- Bump rewrite-clj to v0.1.1.47
+- [#1619](https://github.com/babashka/babashka/issues/1619): Fix reflection issue with `Thread/sleep` in `core.async/timeout`
+- Support interop on `java.util.stream.IntStream`
+- [#1513](https://github.com/babashka/babashka/issues/1513): Fix interop on `Thread/sleep` with numbers that aren't already longs
+- Bump babashka.cli to 0.7.53
+- Fix [#babashka.nrepl/66](https://github.com/babashka/babashka.nrepl/issues/66)
+- Various nREPL server improvements (classpath op, file lookup information for `cider-find-var`)
+- Bump cheshire to 5.12.0
+
+## 1.3.184 (2023-08-22)
+
+- Remove leftover debugging output from deps.clj
+
+## 1.3.183 (2023-08-22)
+
+- [#1592](https://github.com/babashka/babashka/issues/1592): expose `sci.core` in babashka
+- [#1596](https://github.com/babashka/babashka/issues/1596): Fix `clojure.java.browse/browse-url` truncates URLs with multiple query parameters on Windows
+- [#1599](https://github.com/babashka/babashka/issues/1599): propagate error from `run` when task does not exist
+- Bump clj-yaml to `1.0.27`
+- [#1604](https://github.com/babashka/babashka/issues/1604): throw `FileNotFoundException` when requiring namespace whose file cannot be found (as JVM Clojure does)
+- Bump integrant CI tests
+- [#1600](https://github.com/babashka/babashka/issues/1600): use pagesize of 64K on linux aarch64, so it works on Asahi linux
+- Expose `selmer.parser/resolve-arg`
+- [#1610](https://github.com/babashka/babashka/issues/1610): expose `babashka.http-client.websocket` namespace
+- Bump `babashka.http-client` to `0.4.14`
+- [#1568](https://github.com/babashka/babashka/issues/1568): warn when task overrides built-in command
+
+## 1.3.182 (2023-07-20)
+
+- [#1579](https://github.com/babashka/babashka/issues/1579): add `clojure.tools.reader/resolve-symbol`
+- [#1581](https://github.com/babashka/babashka/issues/1581): `bb print-deps`: sort dependencies ([@teodorlu](https://github.com/teodorlu))
+- Upgrade `babashka.http-client` to `0.4.12`, fixes `:insecure` option
+- Bump [edamame](https://github.com/borkdude/edamame) to `1.3.23`: fixes infinite loop with reader conditional expression
+- Bump [Selmer](https://github.com/yogthos/Selmer) to Bumping to `1.12.59`
+- Bump [deps.clj](https://github.com/borkdude/deps.clj) with more fixes which should make downloading/installation of tools jar more robust
+- Add `javax.net.ssl.X509ExtendedTrustManager` class
+- Bump [babashka.process](https://github.com/babashka/process): accept path or file as `:dir` argument
+- Bump [hiccup](https://github.com/weavejester/hiccup) to `2.0.0-RC1`
+
+## 1.3.181 (2023-06-13)
+
+- [#1575](https://github.com/babashka/babashka/issues/1575): fix command line parsing problem with `-e` + `*command-line-args*`
+- [#1576](https://github.com/babashka/babashka/issues/1576): make downloading/unzipping of deps.clj tools .zip file more robust
+
+## 1.3.180 (2023-05-28)
+
+- [#1524](https://github.com/babashka/babashka/issues/1524): Remove dynamic builds for linux-aarch64 ([@lispyclouds](https://github.com/lispyclouds))
+- [#1577](https://github.com/babashka/babashka/issues/1557): Add support for `babashka.process/exec` after namespace reload of `babashka.process` ([@lread](https://github.com/lread))
+- [#1548](https://github.com/babashka/babashka/issues/1548): shell and sh should respect `babashka.process/*defaults*`
+- [#1524](https://github.com/babashka/babashka/issues/1524): deprecate (remove) linux-aarch64 dynamic binary build
+- Expose `org.graalvm.nativeimage.ProcessProperties/exec`
+- Bump `babashka.http-client` to `0.3.11`
+- Bump `babashka.fs` to `0.4.19`
+- Bump `babashka.process` to `0.5.21`
+
+## 1.3.179 (2023-04-26)
+
+- [#1544](https://github.com/babashka/babashka/issues/1544): `:local/root` in script-adjacent bb.edn should resolve relative to script
+- [#1545](https://github.com/babashka/babashka/issues/1545): Adjacent `bb.edn` not respected with explicit `-f` option
+- [#1546](https://github.com/babashka/babashka/issues/1546): add `.contains` for vector and lazy-seq
+
+## 1.3.178 (2023-04-21)
+
+- Fix regression with [#1541](https://github.com/babashka/babashka/issues/1541)
+
+## 1.3.177 (2023-04-21)
+
+- [#1541](https://github.com/babashka/babashka/issues/1541): respect `bb.edn`
+ adjacent to invoked file. This eases writing system-global scripts from
+ projects without using bbin. See [docs](https://book.babashka.org/#_script_adjacent_bb_edn).
+- [#1523](https://github.com/babashka/babashka/pull/1523): Reduce the size of the Docker images ([@raszi](https://github.com/raszi))
+- Upgrade deps.clj to v1.11.1.1273
+- Upgrade transit-clj to 1.0.333
+- Add `java.security.cert.CertificateFactory`
+- Bump clj-yaml to 1.0.26
+- Bump edamame to 1.3.21
+- Add `UnsupportedOperationException`
+- Bump babashka CLI to 0.7.51
+- Bump babashka http-client to 0.2.9
+- Add `--install-exit-handlers` to native-image build to support shutdown hook + SIGTERM
+
+## 1.3.176 (2023-03-18)
+
+- Upgrade http-client to 0.1.8, fixes binary file uploads (which messed up the previous release)
+- Downgrade org.flatland/ordered to 1.5.9 due to this [issue](https://github.com/clj-commons/ordered/issues/71)
+
+## 1.3.175 (2023-03-18)
+
+- [#1507](https://github.com/babashka/babashka/issues/1507): Expose methods on java.lang.VirtualThread ([@lispyclouds](https://github.com/lispyclouds))
+- [#1510](https://github.com/babashka/babashka/issues/1510): add virtual thread interop on `Thread`
+- [#1511](https://github.com/babashka/babashka/issues/1511): support for domain sockets
+- [#1521](https://github.com/babashka/babashka/issues/1521): push images to GHCR ([@lispyclouds](https://github.com/lispyclouds))
+- Bump edamame to 1.3.20
+- Bump deps.clj to 1.11.1.1257
+- Bump org.flatland/ordered to 1.15.10
+- Support `clojure.lang.MapEntry/create`
+- clojure.core.async `go` macro now uses virtual threads
+- Bump babashka.cli to 0.6.50
+- Bump http-client to 0.1.7
+
+## 1.2.174 (2023-03-01)
+
+- Use GraalVM 22.3.1 on JDK 19.0.2. This adds virtual thread support. See [demo](https://twitter.com/borkdude/status/1572222344684531717).
+- Expose more `jaxax.crypto` classes
+- Add more `java.time` and related classes with the goal of supporting [juxt.tick](https://github.com/juxt/tick) ([issue](https://github.com/juxt/tick/issues/86))
+- Compatibility with [kaocha](https://github.com/lambdaisland/kaocha) test runner
+- [#1000](https://github.com/babashka/babashka/issues/1000): add lib tests for xforms ([@bobisageek](https://github.com/bobisageek))
+- [#1482](https://github.com/babashka/babashka/issues/1482): make loading of libs thread safe
+- [#1487](https://github.com/babashka/babashka/issues/1487): `babashka.tasks/clojure` should be supported without arguments to start a REPL
+- [#1496](https://github.com/babashka/babashka/issues/1496): Add `set-agent-send-executor!` and `set-agent-send-off-executor!`
+- [#1489](https://github.com/babashka/babashka/issues/1489): Don't overwrite non-empty, non-jar files when writing uberscript/uberjar ([@bobisageek](https://github.com/bobisageek))
+- [#1506](https://github.com/babashka/babashka/issues/1506): `:exec-args` in task should override `:exec-args` on fn metadata
+- [#1501](https://github.com/babashka/babashka/issues/1501): equals on deftype
+- Add support for `.getWatches` on atoms
+- Bump `babashka.fs` to `0.3.17`
+- Bump `deps.clj` to `1.11.1.1237`
+- Bump `babashka.http-client` to `0.1.5`
+- Bump `babashka.cli` to `0.6.46`
+
+## 1.1.173 (2023-02-04)
+
+- [#1473](https://github.com/babashka/babashka/issues/1473): support `--config` in other dir + `:local/root` ([@lispyclouds](https://github.com/lispyclouds))
+- Compatibility with `clojure.tools.namespace.repl/refresh` and `clojure.java.classpath`
+- `(clojure.lang.RT/baseLoader)` now returns classloader with babashka dependencies on classpath
+- Support reading tags from `data_readers.clj` and `data_readers.cljc`
+- Don't exit REPL when `babashka.deps/add-deps` fails
+- Fix [#1474](https://github.com/babashka/babashka/issues/1474): when `.bb` file is in different artifact, `.clj` file is loaded first if it appears first on classpath
+- Support for `*loaded-libs*` and `(loaded-libs)`
+- Bump rewrite-clj to `1.1.46`
+- Bump http-client to `0.0.3`
+- Bump fs to `0.2.15`
+- Bump process to `0.4.16`
+
+## 1.1.172 (2023-01-23)
+
+- [#1472](https://github.com/babashka/babashka/issues/1472): fix tokenization of `babashka.tasks/clojure`: command was tokenized twice (regression was introduced in `1.0.168`)
+- **BREAKING**: Bump `babashka.process`: change default for `:out :append` to `:out :write`. This default is undocumented so the impact should be small.
+
+## 1.1.171 (2023-01-23)
+
+- [#1467](https://github.com/babashka/babashka/issues/1467): **BREAKING**: avoid printing results, unless `--prn` is enabled (aside from `-e`, `-o` and `-O`).
+- Include [http-client](https://github.com/babashka/http-client) as built-in library
+- SCI: support `add-watch` on vars
+- Compatibility with [eftest](https://github.com/weavejester/eftest) test runner (see [demo](https://twitter.com/borkdude/status/1616886788898885632))
+- Add classes:
+ - `java.util.concurrent.Callable`
+ - `java.util.concurrent.ExecutorService`
+- Expose `clojure.main` `main` and `repl-caught`
+- Switch `clojure.test/*report-counters*` to ref instead of atom for compatibility with [kaocha](https://github.com/lambdaisland/kaocha)
+- Allow `java.io.OutputStream` to be proxied, for [kaocha](https://github.com/lambdaisland/kaocha)
+- Support qualified method names in `proxy` and ignore namespace
+
+## 1.0.170 (2023-01-19)
+
+- [#1463](https://github.com/babashka/babashka/issues/1463): Add `java.util.jar.Attributes` class ([@jeroenvandijk](https://github.com/jeroenvandijk))
+- [#1456](https://github.com/babashka/babashka/issues/1456): allow `*warn-on-reflection*` and `*unchecked-math*` to be set in socket REPL and nREPL ([@axks](https://github.com/axks))
+- SCI: macroexpansion error location improvement
+- Add compatibility with [tab](https://github.com/eerohele/tab) and [solenoid](https://github.com/adam-james-v/solenoid)
+- Bump babashka.cli and babashka.fs
+- New classes:
+ - `java.util.jar.Attributes`
+ - `java.util.concurrent.ThreadFactory`
+ - `java.lang.Thread$UncaughtExceptionHandler`
+ - `java.lang.Thread$UncaughtExceptionHandler`
+ - `java.util.concurrent.BlockingQueue`
+ - `java.util.concurrent.ArrayBlockingQueue`
+ - `java.util.concurrent.ThreadFactory`
+ - `java.lang.Thread$UncaughtExceptionHandler`
+ - `java.util.concurrent.Semaphore`
+- Expose more httpkit.server functions: `with-channel`, `on-close`, `close`
+
+## 1.0.169 (2023-01-03)
+
- Implement `ns`, `lazy-seq` as macro
- Support `--dev-build` flag in installation script
- [#1451](https://github.com/babashka/babashka/issues/1451): Allow passing explicit file and line number to clojure.test ([@matthewdowney](https://github.com/matthewdowney))
@@ -16,6 +262,11 @@ A preview of the next release can be installed from
- [#1446](https://github.com/babashka/babashka/issues/1446): add `pprint/code-dispatch`
- Update zlib to version `1.2.13` ([@thiagokokada](https://github.com/thiagokokada))
- [#1454](https://github.com/babashka/babashka/issues/1454): Add `babashka.process` to `print-deps` output
+- Update `deps.clj` / clojure tools to `1.11.1.1208`
+- Add `reader-conditional` function
+- Fix pretty printing (with `clojure.pprint`) of vars
+- Upgrade built-in `spec.alpha`
+- SCI performance improvements: faster JVM interop
## 1.0.168 (2022-12-07)
@@ -625,7 +876,7 @@ Babashka.pods:
- Add `babashka.task` `System` property [#837](https://github.com/babashka/babashka/issues/837)
- Allow thread-first with `shell` like `babashka.process` [#829](https://github.com/babashka/babashka/issues/829)
-## 0.4.0
+## 0.4.0 (2021-05-08)
Babashka proper:
@@ -635,7 +886,7 @@ Babashka proper:
[jasentaa](https://github.com/rm-hull/jasentaa) parser combinator library
- Update Selmer to 1.12.40
-Sci:
+SCI:
- Better error msg for protocol not found or class
@@ -1205,6 +1456,14 @@ Details about releases prior to v0.1.0 can be found
## Breaking changes
+### v1.1.172
+
+- Bump `babashka.process`: change default for `:out :append` to `:out :write`. This default is undocumented so the impact should be small.
+
+### v1.1.171
+
+- [#1467](https://github.com/babashka/babashka/issues/1467): avoid printing results, unless `--prn` is enabled (aside from `-e`, `-o` and `-O`).
+
### v0.2.4
- Remove cheshire smile functions [#658](https://github.com/babashka/babashka/issues/658)
diff --git a/Dockerfile b/Dockerfile
index f9ad88b3..d109f1ed 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,25 +5,25 @@ RUN apt update
RUN apt install --no-install-recommends -yy build-essential zlib1g-dev
WORKDIR "/opt"
-ENV GRAALVM_VERSION="22.3.0"
+ENV GRAALVM_VERSION="22"
ARG TARGETARCH
# Do not set those directly, use TARGETARCH instead
ENV BABASHKA_ARCH=
ENV GRAALVM_ARCH=
RUN if [ "${TARGETARCH}" = "" ] || [ "${TARGETARCH}" = "amd64" ]; then \
- export GRAALVM_ARCH=amd64; export BABASHKA_ARCH=x86_64; \
+ export GRAALVM_ARCH=x64; export BABASHKA_ARCH=x86_64; \
elif [ "${TARGETARCH}" = "arm64" ]; then \
export GRAALVM_ARCH=aarch64; \
fi && \
echo "Installing GraalVM for ${GRAALVM_ARCH}" && \
- curl -sLO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${GRAALVM_VERSION}/graalvm-ce-java11-linux-${GRAALVM_ARCH}-${GRAALVM_VERSION}.tar.gz && \
- tar -xzf graalvm-ce-java11-linux-${GRAALVM_ARCH}-${GRAALVM_VERSION}.tar.gz && \
- rm graalvm-ce-java11-linux-${GRAALVM_ARCH}-${GRAALVM_VERSION}.tar.gz
+ curl -sLO https://download.oracle.com/graalvm/21/archive/graalvm-jdk-${GRAALVM_VERSION}_linux-${GRAALVM_ARCH}_bin.tar.gz
+ mkdir "graalvm-$GRAALVM_VERSION"
+ tar -xzf graalvm-jdk-${GRAALVM_VERSION}_linux-${GRAALVM_ARCH}_bin.tar.gz -C graalvm --strip-components 1
ARG BABASHKA_XMX="-J-Xmx4500m"
-ENV GRAALVM_HOME="/opt/graalvm-ce-java11-${GRAALVM_VERSION}"
-ENV JAVA_HOME="/opt/graalvm-ce-java11-${GRAALVM_VERSION}/bin"
+ENV GRAALVM_HOME="/opt/graalvm-$GRAALVM_VERSION"
+ENV JAVA_HOME="$GRAALVM_HOME/bin"
ENV PATH="$JAVA_HOME:$PATH"
ENV BABASHKA_XMX=$BABASHKA_XMX
@@ -73,7 +73,9 @@ RUN ./script/compile
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl \
- && mkdir -p /usr/local/bin
+ && rm -rf /var/lib/apt/lists/* \
+ && mkdir -p /usr/local/bin
+
COPY --from=BASE /opt/target/metabom.jar /opt/babashka-metabom.jar
COPY --from=BASE /opt/bb /usr/local/bin/bb
CMD ["bb"]
diff --git a/Dockerfile.alpine b/Dockerfile.alpine
index f1b10a07..bd32c6e5 100644
--- a/Dockerfile.alpine
+++ b/Dockerfile.alpine
@@ -13,8 +13,8 @@ RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswit
# TODO: Run actual native tests when they are ported
-RUN bb -e "(curl/get \"https://httpstat.us/200\")" # cURL http test
-RUN bb -e "(require '[org.httpkit.client :as http]) (when-let [error (:error @(http/get \"https://httpstat.us/200\"))] (throw error))" # JVM http test
+RUN bb -e "(curl/get \"https://clojure.org\")" # cURL http test
+RUN bb -e "(require '[org.httpkit.client :as http]) (when-let [error (:error @(http/get \"https://clojure.org\"))] (throw error))" # JVM http test
RUN bb -e "(.length \"Hello, Babashka\")" # Java interop test
RUN bb -e "(require '[babashka.pods :as pods]) (pods/load-pod 'org.babashka/go-sqlite3 \"0.0.1\") (require '[pod.babashka.go-sqlite3 :as sqlite]) (sqlite/execute! \"/tmp/foo.db\" [\"SELECT 1 + 1\"])" # Pod test
@@ -23,7 +23,7 @@ FROM alpine:3
RUN apk --no-cache add curl ca-certificates tar && \
curl -Ls https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk > /tmp/glibc-2.28-r0.apk && \
- apk add --allow-untrusted --force-overwrite /tmp/glibc-2.28-r0.apk
+ apk add --allow-untrusted --force-overwrite /tmp/glibc-2.28-r0.apk && rm /tmp/glibc-2.28-r0.apk
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
COPY metabom.jar /opt/babashka-metabom.jar
diff --git a/Dockerfile.ci b/Dockerfile.ci
index 6d8c454b..9fb0afe6 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -2,6 +2,7 @@ FROM ubuntu:latest
RUN apt-get update \
&& apt-get install -y curl \
+ && rm -rf /var/lib/apt/lists/* \
&& mkdir -p /usr/local/bin
ARG TARGETARCH
diff --git a/README.md b/README.md
index 75a23601..058d7fc2 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,28 @@ $ ls | bb -i '(filter fs/directory? *input*)'
bb took 4ms.
```
+## Support :heart:
+
+You can support this project via [Github
+Sponsors](https://github.com/sponsors/borkdude),
+[OpenCollective](https://opencollective.com/babashka),
+[Ko-fi](https://ko-fi.com/borkdude) or indirectly via [Clojurists
+Together](https://www.clojuriststogether.org/).
+
+
+
+Top sponsors
+
+- [Clojurists Together](https://clojuriststogether.org/)
+- [Roam Research](https://roamresearch.com/)
+- [Nextjournal](https://nextjournal.com/)
+- [Toyokumo](https://toyokumo.co.jp/)
+- [Cognitect](https://www.cognitect.com/)
+- [Kepler16](https://kepler16.com/)
+- [Adgoji](https://www.adgoji.com/)
+
+
+
## Babashka users
See [companies](doc/companies.md) for a list of companies using babashka.
@@ -82,7 +104,7 @@ and is unlikely to change. Changes may happen in other parts of babashka,
although we will try our best to prevent them. Always check the release notes or
[CHANGELOG.md](CHANGELOG.md) before upgrading.
-### Talk
+## Talk
To get an overview of babashka, you can watch this talk ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)):
@@ -93,6 +115,11 @@ To get an overview of babashka, you can watch this talk ([slides](https://speake
The [babashka book](https://book.babashka.org) contains detailed information
about how to get the most out of babashka scripting.
+There is also the book [Babashka Babooka](https://www.braveclojure.com/quests/babooka/),
+by Daniel Higginbotham, who has also helped a lot of people learn Clojure with
+[Clojure for the Brave and
+True](https://www.braveclojure.com/clojure-for-the-brave-and-true/).
+
## Examples
Read the output from a shell command as a lazy seq of strings:
@@ -127,7 +154,7 @@ File `pst.clj`:
```
``` shell
-$ pst.clj
+$ bb pst.clj
05:17
```
@@ -148,11 +175,6 @@ Install:
brew install borkdude/brew/babashka
-
-
-
-
-
Upgrade:
brew upgrade babashka
@@ -190,13 +212,25 @@ linux binary.
### asdf
-[asdf](https://github.com/asdf-vm/asdf) is an extendable version manager for linux and macOS.
+[asdf](https://github.com/asdf-vm/asdf) is an extendable version manager for linux and macOS. Note that asdf will add significant startup time to any babashka script, consider using [mise](#mise) instead.
Babashka can be installed using a plugin as follows:
- asdf plugin add babashka
+ asdf plugin add babashka https://github.com/pitch-io/asdf-babashka
asdf install babashka latest
+### mise
+
+[mise](https://mise.jdx.dev/) is a development environment setup tool for linux and macOS.
+
+Install:
+
+ mise use --global babashka@latest
+
+Upgrade:
+
+ mise upgrade babashka
+
### Windows
#### Scoop
@@ -283,6 +317,12 @@ You may also download a binary from
[Github](https://github.com/babashka/babashka/releases). For linux there is a
static binary available which can be used on Alpine.
+### CI
+
+- On Github Actions it's recommended to use [setup-clojure](https://github.com/DeLaGuardo/setup-clojure) with `bb: latest`.
+- You can use the [installer script](https://github.com/babashka/babashka#installer-script) on any non-Windows CI system. CircleCI requires `sudo`.
+- On Appveyor + Windows you can use a bit of [Powershell](https://github.com/clj-kondo/clj-kondo/blob/39b5cb2b0d3d004c005e8975b6fafe0e314eec68/appveyor.yml#L60-L64).
+
## Docker
Check out the image on [Docker hub](https://hub.docker.com/r/babashka/babashka/).
@@ -358,6 +398,10 @@ https://babashka.org[image:https://raw.githubusercontent.com/babashka/babashka/m
+## Swag
+
+- [t-shirt](https://www.etsy.com/listing/1241766068/babashka-clj-kondo-nbb-shirt)
+
## [Pods](https://github.com/babashka/babashka.pods)
Pods are programs that can be used as a Clojure library by
@@ -406,11 +450,21 @@ handling of SIGINT and SIGPIPE. This can be done by setting
## Articles, podcasts and videos
-- [Babashka: How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure](https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746) by Michiel Borkent
+- [Blambda analyses sites](https://jmglov.net/blog/2023-01-04-blambda-analyses-sites.html) by Josh Glover
+- [The wizard of HOP - How we built the web based HOP CLI Settings Editor using Babashka and Scittle](https://www.gethop.dev/post/the-wizard-of-hop-how-we-built-the-web-based-hop-cli-settings-editor-using-babashka-and-scittle) by Bingen Galartza
+- [Simple TUIs with Babashka and Gum](https://rattlin.blog/bbgum.html) by Rattlin.blog
+- [Babashka And Dialog Part Ii: Announcing The Bb-Dialog Library](https://www.pixelated-noise.com/blog/2023/01/20/bb-dialog-announcement/index.html) by A.C. Danvers
+- [Babashka Babooka](https://www.braveclojure.com/quests/babooka/): Write Command-Line Clojure by Daniel Higginbotham
+- [Re-Writing a GlobalProtect OpenConnect VPN Connect script in Babashka](https://tech.toryanderson.com/2023/01/14/re-writing-a-globalprotect-openconnect-vpn-connect-script-in-babashka/) by Tory Anderson
+- [Babashka: How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure](https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746) by Michiel Borkent (Japanese version [here]((https://logico-jp.io/2023/01/07/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure/)))
- [Adding Prompts To Your Babashka Scripts With Dialog](https://www.pixelated-noise.com/blog/2022/12/09/dialog-and-babashka/index.html) by A.C. Danvers
+- [Scraping an HTML dictionary with Babashka and Bootleg](https://blog.exupero.org/scraping-an-html-dictionary-with-babashka-and-bootleg/) by exupero
- [Using Babashka to Get Electricity Prices](https://www.karimarttila.fi/clojure/2022/12/04/using-babashka-to-get-electricity-prices.html) by Kari Marttila
+- [How to Do Things With Babashka](https://presumably.de/how-to-do-things-with-babashka.html) by Paulus Esterhazy (2022-12)
+- [Using nREPL as a system interface](https://yogthos.net/posts/2022-11-26-nREPL-system-interaction.html) by Dmitri Sotnikov
- [Manage git hooks with babashka tasks](https://blaster.ai/blog/posts/manage-git-hooks-w-babashka.html) by Mykhaylo Bilyanskyy
- [Messing around with babashka](https://ian-muge.medium.com/messing-around-with-babashka-f181a9003faa) by Ian Muge
+- Introducing [bbin](https://radsmith.com/bbin) by Radford Smith (2022-09)
- [Deleting AWS Glacier vaults with babashka](https://javahippie.net/clojure/2022/07/23/deleting-aws-glacier-vaults-with-babashka.html) by Tim Zöller
- [Recursive document transformations with Pandoc and Clojure](https://play.teod.eu/document-transform-pandoc-clojure/) by Teodor Heggelund
- [Blambda!](https://jmglov.net/blog/2022-07-03-blambda.html) by Josh Glover
@@ -497,47 +551,10 @@ commit](https://github.com/babashka/babashka/commit/02c7c51ad4b2b1ab9aa95c26a744
Thanks to all the people that contributed to babashka:
-- [Adgoji](https://www.adgoji.com/) for financial support
- [CircleCI](https://circleci.com/) for CI and additional support
- [Nikita Prokopov](https://github.com/tonsky) for the logo
- [Contributors](https://github.com/babashka/babashka/graphs/contributors) and
other users posting issues with bug reports and ideas
-- [Github sponsors](https://github.com/sponsors/borkdude)
-- [OpenCollective sponsors](https://opencollective.com/babashka)
-- [Clojurists Together](https://www.clojuriststogether.org/)
-
-### Code Contributors
-
-This project exists thanks to all the people who contribute. [[Contribute](doc/dev.md)].
-
-
-### Financial Contributors
-
-#### Github Sponsors
-
-- [Dig Gashinsky](https://github.com/digash)
-
-#### OpenCollective
-Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/babashka/contribute)]
-
-##### Individuals
-
-
-
-##### Organizations
-
-Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/babashka/contribute)]
-
-
-
-
-
-
-
-
-
-
-
## License
diff --git a/appveyor.yml b/appveyor.yml
index 7e60e61c..16dda71d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,13 +2,13 @@
version: "v-{build}"
-image: Visual Studio 2017
+image: Visual Studio 2022
clone_folder: C:\projects\babashka
environment:
- GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-ce-java11-22.3.0
- JAVA_HOME: C:\projects\babashka\graalvm\graalvm-ce-java11-22.3.0
+ GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-jdk-22+36.1
+ JAVA_HOME: C:\projects\babashka\graalvm\graalvm-jdk-22+36.1
BABASHKA_XMX: "-J-Xmx5g"
skip_commits:
@@ -23,6 +23,9 @@ cache:
clone_script:
- cmd: git config --global core.autocrlf true
+
+- cmd: git config --global core.symlinks true
+
- ps: >-
if(-not $env:APPVEYOR_PULL_REQUEST_NUMBER) {
git clone -q --branch=$env:APPVEYOR_REPO_BRANCH https://github.com/$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER
@@ -36,9 +39,12 @@ clone_script:
}
- cmd: git submodule update --init --recursive
+- cmd: git reset --hard
+
build_script:
+# TODO: Extract the zip by removing the top level folder to remove the hardcoded path for GRAALVM_HOME
- cmd: >-
- powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.3.0/graalvm-ce-java11-windows-amd64-22.3.0.zip', 'graalvm.zip') }"
+ powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://download.oracle.com/graalvm/22/archive/graalvm-jdk-22_windows-x64_bin.zip', 'graalvm.zip') }"
powershell -Command "if (Test-Path('graalvm')) { return } else { Expand-Archive graalvm.zip graalvm }"
@@ -55,8 +61,6 @@ build_script:
# see https://github.com/quarkusio/quarkus/pull/7663
- cmd: >-
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
-
call script/uberjar.bat
call script/compile.bat
@@ -69,11 +73,15 @@ build_script:
bb --config .build/bb.edn --deps-root . release-artifact %zip%
+before_test:
+- cmd: >-
set BABASHKA_CLASSPATH=
set BABASHKA_TEST_ENV=native
- call script/test.bat
+test_script:
+- cmd: >-
+ call script/test.bat :windows
call script/run_lib_tests.bat
diff --git a/babashka.curl b/babashka.curl
index 99e6d3ba..e936acd4 160000
--- a/babashka.curl
+++ b/babashka.curl
@@ -1 +1 @@
-Subproject commit 99e6d3ba7a7252284b43f9de7d91d3433ecfa8f0
+Subproject commit e936acd40544eb637b6041c7e89454b21eb7ee34
diff --git a/babashka.nrepl b/babashka.nrepl
index ad763a78..edd3d613 160000
--- a/babashka.nrepl
+++ b/babashka.nrepl
@@ -1 +1 @@
-Subproject commit ad763a78f1bc327a493ff0b650aa5408ecbf4819
+Subproject commit edd3d613bfb9bf3adabfd0bda5c3f5c6ee85ec20
diff --git a/deps.clj b/deps.clj
index 2d185718..aa143f01 160000
--- a/deps.clj
+++ b/deps.clj
@@ -1 +1 @@
-Subproject commit 2d185718ba2871c96e6cb4a4181d1dcf9d8fde86
+Subproject commit aa143f015469884d91f812e16b977ecccdcc2c04
diff --git a/deps.edn b/deps.edn
index 692d7724..e73a12f7 100644
--- a/deps.edn
+++ b/deps.edn
@@ -17,10 +17,10 @@
"depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources"
"resources" "sci/resources"
- "reify/src"],
- :deps {org.clojure/clojure {:mvn/version "1.11.1"},
+ "impl-java/src"],
+ :deps {org.clojure/clojure {:mvn/version "1.11.2"},
org.babashka/sci {:local/root "sci"}
- org.babashka/babashka.impl.reify {:mvn/version "0.1.3"}
+ org.babashka/babashka.impl.java {:mvn/version "0.1.8"}
org.babashka/sci.impl.types {:mvn/version "0.0.2"}
babashka/babashka.curl {:local/root "babashka.curl"}
babashka/fs {:local/root "fs"}
@@ -29,28 +29,30 @@
org.clojure/core.async {:mvn/version "1.6.673"},
org.clojure/tools.cli {:mvn/version "1.0.214"},
org.clojure/data.csv {:mvn/version "1.0.0"},
- cheshire/cheshire {:mvn/version "5.11.0"}
+ cheshire/cheshire {:mvn/version "5.13.0"}
org.clojure/data.xml {:mvn/version "0.2.0-alpha8"}
- clj-commons/clj-yaml {:mvn/version "0.7.169"}
- com.cognitect/transit-clj {:mvn/version "1.0.329"}
+ clj-commons/clj-yaml {:mvn/version "1.0.27"}
+ com.cognitect/transit-clj {:mvn/version "1.0.333"}
org.clojure/test.check {:mvn/version "1.1.1"}
nrepl/bencode {:mvn/version "1.1.0"}
seancorfield/next.jdbc {:mvn/version "1.1.610"}
org.postgresql/postgresql {:mvn/version "42.2.18"}
org.hsqldb/hsqldb {:mvn/version "2.5.1"}
datascript/datascript {:mvn/version "1.0.1"}
- http-kit/http-kit {:mvn/version "2.6.0-RC1"}
+ http-kit/http-kit {:mvn/version "2.8.0-RC1"}
babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"}
org.clojure/core.match {:mvn/version "1.0.0"}
- hiccup/hiccup {:mvn/version "2.0.0-alpha2"}
- rewrite-clj/rewrite-clj {:mvn/version "1.1.45"}
- selmer/selmer {:mvn/version "1.12.50"}
- com.taoensso/timbre {:mvn/version "6.0.1"}
+ hiccup/hiccup {:mvn/version "2.0.0-RC1"}
+ rewrite-clj/rewrite-clj {:mvn/version "1.1.47"}
+ selmer/selmer {:mvn/version "1.12.59"}
+ com.taoensso/timbre {:mvn/version "6.5.0"}
org.clojure/tools.logging {:mvn/version "1.1.0"}
org.clojure/data.priority-map {:mvn/version "1.1.0"}
insn/insn {:mvn/version "0.5.2"}
org.clojure/core.rrb-vector {:mvn/version "0.1.2"}
- org.babashka/cli {:mvn/version "0.6.41"}}
+ org.babashka/cli {:mvn/version "0.8.59"}
+ org.babashka/http-client {:mvn/version "0.4.18"}
+ org.flatland/ordered {:mvn/version "1.15.12"}}
:aliases {:babashka/dev
{:main-opts ["-m" "babashka.main"]}
:profile
@@ -64,7 +66,7 @@
{:extra-paths ["process/src" "process/test" "test-resources/lib_tests"]
:extra-deps {org.clj-commons/clj-http-lite {:mvn/version "0.4.392"}
#_#_org.babashka/spec.alpha {:git/url "https://github.com/babashka/spec.alpha"
- :sha "0dec1f88cbde74a0470b454396f09a03adb4ae39"}
+ :sha "0dec1f88cbde74a0470b454396f09a03adb4ae39"}
lambdaisland/regal {:mvn/version "0.0.143"}
cprop/cprop {:mvn/version "0.1.16"}
comb/comb {:mvn/version "0.1.1"}
@@ -106,7 +108,7 @@
exoscale/coax {:mvn/version "1.0.0-alpha14"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
expound/expound {:mvn/version "0.8.10"}
- integrant/integrant {:mvn/version "0.8.0"}
+ integrant/integrant {:git/url "https://github.com/weavejester/integrant", :git/sha "a9fd7c02bd7201f36344b47142badc3c3ef22f88"}
com.stuartsierra/dependency {:mvn/version "1.0.0"}
listora/again {:mvn/version "1.0.0"}
org.clojure/tools.gitlibs {:mvn/version "2.4.172"}
@@ -165,7 +167,12 @@
:git/sha "1a29775a3d286f9f6fe3f979c78b6e2bf298d5ba"}
com.github.rawleyfowler/sluj {:git/url "https://github.com/rawleyfowler/sluj"
:git/sha "4a92e772b4e07bf127423448d4140748b5782198"
- :deps/manifest :deps}}
+ :deps/manifest :deps}
+ net.cgrand/xforms {:git/url "https://github.com/cgrand/xforms"
+ :git/sha "550dbc150a79c6ecc148d8a7e260e10bc36321c6"
+ :deps/manifest :deps}
+ prismatic/plumbing {:git/url "https://github.com/plumatic/plumbing",
+ :git/sha "424bc704f2db422de34269c139a5494314b3a43b"}}
:classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil}}
:clj-nvd
diff --git a/depstar b/depstar
index c419b8c8..2bf9d3c9 160000
--- a/depstar
+++ b/depstar
@@ -1 +1 @@
-Subproject commit c419b8c82041855d55593c5b561fc7cea8234712
+Subproject commit 2bf9d3c9f15298d7dd9de033674a42f830e23d6f
diff --git a/doc/build.md b/doc/build.md
index 4de497e0..6f81d189 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -3,24 +3,24 @@
## Prerequisites
- Install [lein](https://leiningen.org/) for producing uberjars
-- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *java11-22.3.0*.
+- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *jdk-22*.
- For Windows, installing Visual Studio 2019 with the "Desktop development
with C++" workload is recommended.
- Set `$GRAALVM_HOME` to the GraalVM distribution directory. On macOS this can look like:
``` shell
- export GRAALVM_HOME=~/Downloads/graalvm-ce-java11-22.3.0/Contents/Home
+ export GRAALVM_HOME=~/Downloads/graalvm-jdk-21.0.0.1/Contents/Home
```
On linux:
``` shell
- export GRAALVM_HOME=~/Downloads/graalvm-ce-java11-22.3.0
+ export GRAALVM_HOME=~/Downloads/graalvm-jdk-21.0.0.1
```
On Windows, from the [Visual Studio 2019 x64 Native Tools Command Prompt](https://github.com/oracle/graal/issues/2116#issuecomment-590470806) or `cmd.exe` (not Powershell):
```
- set GRAALVM_HOME=%USERPROFILE%\Downloads\graalvm-ce-java11-22.3.0
+ set GRAALVM_HOME=%USERPROFILE%\Downloads\graalvm-ce-jdk-21.0.0.1
```
If you are not running from the x64 Native Tools Command Prompt, you will need to set additional environment variables using:
```
@@ -62,7 +62,7 @@ take long to complete.
### Alternative: Build inside Docker
-To build a Linux version of babashka, you can use `docker build`, enabling the
+To build a Linux version of babashka, you can use `docker build`, enabling the
desired features via `--build-arg` like this:
```shell
@@ -113,8 +113,8 @@ Babashka supports the following feature flags:
| `BABASHKA_FEATURE_ORACLEDB` | Includes the [Oracle](https://www.oracle.com/database/technologies/appdev/jdbc.html) JDBC driver | `false` |
| `BABASHKA_FEATURE_DATASCRIPT` | Includes [datascript](https://github.com/tonsky/datascript) | `false` |
| `BABASHKA_FEATURE_LANTERNA` | Includes [clojure-lanterna](https://github.com/babashka/clojure-lanterna) | `false` |
-| `BABASHKA_FEATURE_LOGGING` | Includes [clojure.tools.logging](https://github.com/clojure/tools.logging) with [taoensso.timbre](https://github.com/ptaoussanis/timbre) as the default implementation| `true` |
-| `BABASHKA_FEATURE_PRIORITY_MAP` | Includes [clojure.data.priority-map](https://github.com/clojure/data.priority-map) | `true` |
+| `BABASHKA_FEATURE_LOGGING` | Includes [clojure.tools.logging](https://github.com/clojure/tools.logging) with [taoensso.timbre](https://github.com/ptaoussanis/timbre) as the default implementation| `true` |
+| `BABASHKA_FEATURE_PRIORITY_MAP` | Includes [clojure.data.priority-map](https://github.com/clojure/data.priority-map) | `true` |
Note that httpkit server is currently experimental, the feature flag could be toggled to `false` in a future release.
diff --git a/doc/companies.md b/doc/companies.md
index b068313a..fe2f79ae 100644
--- a/doc/companies.md
+++ b/doc/companies.md
@@ -64,6 +64,7 @@ Sponsoring via [Cognitect](https://www.cognitect.com/).
- [Fluree](https://flur.ee/)
- [Hi](https://www.hi.group/)
- [Juxt](https://www.juxt.pro/)
+- [Kleene](https://www.kleene.ai/)
- [Latacora](https://www.latacora.com/)
- [Metosin](https://www.metosin.fi/en/)
- [Nextdoc](https://www.nextdoc.io/)
diff --git a/doc/dev.md b/doc/dev.md
index 872cfa8e..ba8d8ab0 100644
--- a/doc/dev.md
+++ b/doc/dev.md
@@ -37,7 +37,7 @@ reasons:
## Requirements
-You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java11-22.3.0.
+You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use jdk-21.0.0.1
## Clone repository
diff --git a/doc/libraries.csv b/doc/libraries.csv
index 7d8c22c1..398b1760 100644
--- a/doc/libraries.csv
+++ b/doc/libraries.csv
@@ -67,6 +67,7 @@ meta-merge/meta-merge,https://github.com/weavejester/meta-merge
metosin/malli,https://github.com/metosin/malli
minimallist/minimallist,https://github.com/green-coder/minimallist
mvxcvi/arrangement,https://github.com/greglook/clj-arrangement
+net.cgrand/xforms,https://github.com/cgrand/xforms
orchestra/orchestra,https://github.com/jeaye/orchestra
org.babashka/spec.alpha,https://github.com/babashka/spec.alpha
org.clj-commons/clj-http-lite,https://github.com/clj-commons/clj-http-lite
@@ -83,7 +84,7 @@ org.clojure/math.combinatorics,https://github.com/clojure/math.combinatorics
org.clojure/math.numeric-tower,https://github.com/clojure/math.numeric-tower
org.clojure/test.check,https://github.com/clojure/test.check
org.clojure/tools.gitlibs,https://github.com/clojure/tools.gitlibs
-org.clojure/tools.namespace,https://github.com/babashka/tools.namespace
+org.clojure/tools.namespace,https://github.com/clojure/tools.namespace
postmortem/postmortem,https://github.com/athos/Postmortem
prismatic/schema,https://github.com/plumatic/schema
progrock/progrock,https://github.com/weavejester/progrock
diff --git a/doc/news.md b/doc/news.md
index f5eb263c..7b3092ec 100644
--- a/doc/news.md
+++ b/doc/news.md
@@ -5,8 +5,234 @@ you have anything to add. Also see
[#babashka](https://twitter.com/hashtag/babashka?src=hashtag_click&f=live) on
Twitter.
-## [2022-07](https://twitter.com/search?q=(%23babashka)%20until%3A2022-08-01%20since%3A2022-07-01&src=typed_query&f=live)
+## 2023-05 ([Twitter](https://twitter.com/search?q=(%23babashka%20OR%20babashka)%20since%3A2023-05-01%20until%3A2023-06-01&src=typed_query&f=live), [Mastodon](https://mastodon.social/tags/babashka))
+### Releases
+
+1.3.178
+
+Mostly a boring maintenance release with lib upgrades!
+
+### Events
+
+- [Babashka-conf](https://babashka.org/conf/) is happening June 10th in
+Berlin. Only a few tickets left! See the [schedule](https://babashka.org/conf/schedule.html). Also you can buy a [conf t-shirt](https://www.etsy.com/listing/1475981599/babashka-conf-berlin-2023-t-shirt) now! See Nikita wearing it [here](https://twitter.com/nikitonsky/status/1658066530800742400)!
+
+Thanks to conference sponsors:
+
+
+
+- Babashka is going to the [Strange Loop](https://www.thestrangeloop.com/) conference!
+
+### Projects
+
+- [beep-boop](https://github.com/pesterhazy/beep-boop): Audible and visual feedback for test runs
+- [panas.example](https://github.com/keychera/panas.example): All htmx examples ported to babashka!
+- [utility-scripts](https://github.com/somecho/utility-scripts): A collection of helper scripts for Clojure, Java, Ledger and Taskwarrior. Written in Clojure
+- [bb-scripts](https://github.com/techconative/bb-scripts): Babashka scripts for common utilities
+- [Launching bb tasks from emacs](https://mastodon.social/@mykhaylo@fosstodon.org/110456087708592838)
+
+### Articles
+
+- [Clojure in security: Docker](https://www.juxt.pro/blog/clojure-in-docker/): mentions babashka and clj-kondo
+- [Changing my mind: Converting a script from bash to Babashka](https://blog.agical.se/en/posts/changing-my-mind--converting-a-script-from-bash-to-babashka/)
+- [How to create a really simple ClojureCLR dependency tool](https://blog.agical.se/en/posts/how-to-create-a-really-simple-clojureclr-dependency-tool/) with babashka
+- [Making a resume with Node.js babashka (nbb)](https://yogthos.net/posts/2023-05-12-nbb-resume.html)
+
+## 2023-04 ([Twitter](https://twitter.com/search?q=(%23babashka%20OR%20babashka)%20since%3A2023-04-01%20until%3A2023-05-01&src=typed_query&f=live), [Mastodon](https://mastodon.social/tags/babashka))
+
+[Babashka-conf](https://babashka.org/conf/) is happening June 10th in
+Berlin. Save the date and/or submit your babashka/clojure-related talk or workshop
+in the CfP!
+
+### Releases
+
+1.3.177
+
+Biggest highlight: `bb.edn` is now respected relative of a script, no matter the directory you invoke it from! See [docs](https://book.babashka.org/#_script_adjacent_bb_edn).
+
+### Projects
+
+- [babashka-dl](https://github.com/mjhika/babashka-dl): simple install script for babashka on windows
+- [instaparse-bb](https://github.com/babashka/instaparse-bb): Use instaparse from babashka, a new release
+
+### Videos
+
+- [Learning clojure w/ @lispyclouds](https://youtu.be/uBTRLBU-83A): a stream with teej_dv, a neovim core dev
+
+## 2023-03 ([Twitter](https://twitter.com/search?q=(%23babashka%20OR%20babashka)%20since%3A2023-03-01%20until%3A2023-04-01&src=typed_query&f=top), [Mastodon](https://mastodon.social/tags/babashka))
+
+### Releases
+
+1.3.176, 1.3.175, 1.2.174:
+
+Biggest highlight: Switch to GraalVM 19 and enable virtual threads!
+
+### Videos
+
+- [Blambda! The sound of babashka and AWS colliding](https://pitch.com/public/03fa9c7e-2b0e-45fb-8a22-d4a4d4d79d24), by Josh Glover from Pitch!
+
+### Projects
+
+- [babashka.json](https://github.com/babashka/json): JSON abstraction library
+- [martian](https://github.com/oliyh/martian) is now babashka compatible!
+- [panas.reload](https://github.com/keychera/panas.reload): a hot reload for babashka serving html+css (or htmx)
+- [cljs-exif-reader](https://git.sr.ht/~rwv/cljs-exif-reader): Extract information from TIFF and JPEG images (works in babashka, despite the name)
+
+### Jobs
+
+- Write babashka at [Cognician](https://twitter.com/RobStuttaford/status/1641694501793038336)!
+
+## 2023-02 ([Twitter](https://twitter.com/search?q=(%23babashka%20OR%20babashka)%20since%3A2023-02-01%20until%3A2023-03-01&src=typed_query&f=live), [Mastodon](https://mastodon.social/tags/babashka))
+
+## Releases
+
+1.1.173: mostly bugfixes
+
+### Articles
+
+- [A technique for live coding simple web pages](https://github.com/whacked/cow/blob/main/a%20technique%20for%20live%20coding%20simple%20web%20pages.md) with babashka
+
+### Videos
+
+- [Stockholm Clojure Meetup Feb 23: Blambda! The sound of Babashka and Lambda colliding](https://www.youtube.com/watch?v=NfgYon96dsE)
+
+### Projects
+
+- [debux](https://github.com/philoskim/debux) is now babaskha-compatible
+- [lines-of-code-bb](https://github.com/matthewdowney/linesofcode-bb): Babashka script to count lines of Clojure code, docs, comments, and more
+- [deps-try](https://github.com/eval/deps-try): a babashka-script to try out Clojure libraries in rebel-readline
+- [bb-dialog](https://github.com/pixelated-noise/bb-dialog) adds support for `--treeview`
+- [A duckduck go CLI with babashka and (bbl)gum](https://mastodon.me.uk/@choffee/109845697304457129)
+- [babashka http-client](https://github.com/babashka/http-client) now supports multipart uploads
+- [sublime-pretty-edn](https://github.com/oakmac/sublime-pretty-edn): Format, Validate, Minify EDN files in Sublime Text
+- [Play console tetris in babashka!](https://twitter.com/borkdude/status/1628473136969576449)
+- [kaocha test runner](https://github.com/lambdaisland/kaocha) became babashka compatible!
+
+## 2023-01 ([Twitter](https://twitter.com/search?q=%28%23babashka%20OR%20babashka%29%20until%3A2023-02-01%20since%3A2023-01-01&src=typed_query&f=live), [Mastodon](https://mastodon.social/tags/babashka))
+
+### Releases
+
+New releases in the past month: 1.0.170 - 1.1.173
+Release highlights:
+
+- Support for `data_readers.clj(c)`
+- Include [http-client](https://github.com/babashka/http-client) as built-in library
+- Compatibility with [clojure.tools.namespace.repl/refresh](https://github.com/clojure/tools.namespace)
+- Compatibility with [clojure.java.classpath](https://github.com/clojure/java.classpath) (and other libraries which rely on `java.class.path` and `RT/baseLoader`)
+- Compatibility with [eftest](https://github.com/weavejester/eftest) test runner (see demo)
+- Compatibility with [cljfmt](https://github.com/weavejester/cljfmt)
+- Support for `*loaded-libs*` and `(loaded-libs)`
+- Support `add-watch` on vars (which adds compatibility with `potemkin.namespaces`)
+- BREAKING: make printing of script results explicit with `--prn`
+
+### Events
+
+- [Babashka Workshop](https://clojure.stream/workshops/babashka) at ClojureStream with Rahul De
+- [Blambda! The sound of Babashka and Lambda colliding](https://www.meetup.com/sthlm-clj/events/291204199/?utm_medium=referral&utm_campaign=share-btn_savedevents_share_modal&utm_source=twitter): sthlm.clj (Stockholm, Sweden)
+
+### Articles
+
+- [Babooka: write command line Clojure](https://www.braveclojure.com/quests/babooka/) by Daniel Higginbotham
+- [Blambda analyses sites](https://jmglov.net/blog/2023-01-04-blambda-analyses-sites.html) by Josh Glover
+- [Babashka: How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure](https://logico-jp.io/2023/01/07/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure/) in Japanese
+- [The wizard of HOP - How we built the web based HOP CLI Settings Editor using Babashka and Scittle](https://www.gethop.dev/post/the-wizard-of-hop-how-we-built-the-web-based-hop-cli-settings-editor-using-babashka-and-scittle) by Bingen Galartza
+- [Simple TUIs with Babashka and Gum](https://rattlin.blog/bbgum.html) by Rattlin.blog
+- [Babashka And Dialog Part Ii: Announcing The Bb-Dialog Library](https://www.pixelated-noise.com/blog/2023/01/20/bb-dialog-announcement/index.html) by A.C. Danvers
+- [Re-Writing a GlobalProtect OpenConnect VPN Connect script in Babashka](https://tech.toryanderson.com/2023/01/14/re-writing-a-globalprotect-openconnect-vpn-connect-script-in-babashka/) by Tory Anderson
+
+### Projects
+
+Projects that were new, had updates or were made compatible with babashka:
+
+- [asdf-babashka](https://github.com/pitch-io/asdf-babashka): babashka plugin for the asdf version manager
+- [babashka-htmx-todoapp](https://github.com/prestancedesign/babashka-htmx-todoapp): Quick example of a todo list SPA using Babashka and HTMX
+- [bblgum](https://github.com/lispyclouds/bblgum): An extremely tiny and simple wrapper around charmbracelet/gum
+- [bb-dialog](https://github.com/pixelated-noise/bb-dialog): A simple wrapper library for working with dialog from Babashka
+- [carve](https://github.com/borkdude/carve): Remove unused Clojure vars
+- [chr](https://github.com/ThaddeusJiang/chr): native commands history report for the default terminal users
+- [clj-kondo-bb](https://github.com/clj-kondo/clj-kondo-bb): Invoke clj-kondo from babashka scripts!
+- [cljfmt](https://github.com/weavejester/cljfmt): A tool for formatting Clojure code
+- [drepl](https://github.com/claytn/drepl): Node JS dependency-repl. The node repl you already know with easy library installations
+- [instaparse-bb](https://github.com/babashka/instaparse-bb): Wrapper library aroud pod-babashka-instaparse
+- [lein2deps](https://github.com/borkdude/lein2deps): Lein project.clj to deps.edn converter
+- [neil](https://github.com/babashka/neil): A CLI to add common aliases and features to deps.edn-based projects
+- [obsidian-babashka](https://github.com/filipesilva/obsidian-babashka): Run Obsidian Clojure(Script) codeblocks in Babashka
+- [pod-babashka-buddy](https://github.com/babashka/pod-babashka-buddy): A pod around buddy core (Cryptographic Api for Clojure)
+- [quickblog](https://github.com/borkdude/quickblog): Light-weight static blog engine for Clojure and babashka
+- [solenoid](https://github.com/adam-james-v/solenoid): A small clojure tool for making little control UIs while using the REPL!
+- [tools.bbuild](https://github.com/babashka/tools.bbuild): babashka version of tools.build
+- [weather](https://gist.github.com/yogthos/f86e63b856e1413180b2262024ece977): command line util for grabbing current weather for a city using OpenWeather API
+
+## [2022-12](https://twitter.com/search?q=%28%23babashka%20OR%20babashka%29%20until%3A2023-01-01%20since%3A2022-12-01&src=typed_query&f=live)
+
+- Releases: [1.0.168](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
+- [How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure](https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746)
+- [http-client](https://github.com/babashka/http-client): a new HTTP client library for babashka
+- [How to Do Things With Babashka](https://presumably.de/how-to-do-things-with-babashka.html) by Paulus Esterhazy (2022-12)
+- [Using Babashka to Get Electricity Prices](https://www.karimarttila.fi/clojure/2022/12/04/using-babashka-to-get-electricity-prices) by Kari Marttila
+- [Adding prompts to your babashka scripts with dialog](https://www.pixelated-noise.com/blog/2022/12/09/dialog-and-babashka/index.html) by A.C. Danvers
+- [Scraping an HTML dictionary with Babashka and Bootleg](https://blog.exupero.org/scraping-an-html-dictionary-with-babashka-and-bootleg/) by exupero
+- [quickblog](https://github.com/borkdude/quickblog) v0.1.0: Light-weight static blog engine for Clojure and babashka
+- [bb-excel](https://github.com/kbosompem/bb-excel): Read Excel Files in babashka scripts
+- [Get paginated list of issues from gitlab with clojure/babashka](https://gist.github.com/MrGung/29d0547fe45316c3438032fd164d42c6) by Steffen Glückselig
+- Install development builds: `bash <(curl https://raw.githubusercontent.com/babashka/babashka/master/install) --dev-build --dir /tmp`
+- [JVM interop improvements in bb](https://twitter.com/borkdude/status/1606280110692352001)
+- [A little trick to have conditional code for babashka in a .clj file without resorting to .cljc reader conditionals](https://twitter.com/borkdude/status/1599067149187764224)
+- [Get Advent of Code input in babashka](https://gist.github.com/jeeger/6e39fea94ce49e33d1fa43f40cc36630) by Jan Seeger
+- [Grabbing current weather for a city using OpenWeather API](https://gist.github.com/yogthos/f86e63b856e1413180b2262024ece977) by Dmitri Sotnikov
+
+## [2022-11](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-12-01%20since%3A2022-11-01&src=typed_query&f=live)
+
+- Releases: [1.0.165 - 1.0.167](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
+- Registration for a [Babashka workshop](https://clojure.stream/workshops/babashka) with Rahul De at ClojureStream is now open!
+- [Tutkain, a Sublime plugin for clojure based on socket REPL now with support for babashka](https://github.com/eerohele/Tutkain)
+- [Manage git hooks in babashka](https://blaster.ai/blog/posts/manage-git-hooks-w-babashka.html) by Mykhaylo Bilyanskyy
+- [Messing around with babashka](Messing around with Babashka) by Ian Muge
+- [A babashka one liner to inspect data in portal](https://twitter.com/borkdude/status/1597505695800516609)
+- [Using nREPL as a system interface](https://yogthos.net/posts/2022-11-26-nREPL-system-interaction.html) by Dmitri Sotnikov
+- [deep-diff2](https://github.com/lambdaisland/deep-diff2) is now babashka-compatible!
+- [A script to normalize auto-resolved keywords](https://github.com/babashka/babashka/blob/master/examples/normalize-keywords.clj)
+- [Sum up page counts of books from Calibre library with babashka](https://gist.github.com/jeeger/d13159fefaee33c771be979639900ebc) by Jan Seeger
+- [Tiny babashka script that returns a random clojure doc](https://gist.github.com/CarnunMP/c592cd3b6e711d56ddd4ca7832b9b251) by Carnun Marcus-Page
+
+
+## [2022-10](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-11-01%20since%3A2022-10-01&src=typed_query&f=live)
+
+- Releases: [1.0.164](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
+- [bb-pod-racer](https://github.com/justone/bb-pod-racer): Speed up development of Babashka pods by Nate Jones
+- [Babashka tasks VSCode plugin](https://marketplace.visualstudio.com/items?itemName=fbeyer.babashka-tasks) by Ferdinand Beyer
+- A [PR](https://github.com/nextjournal/clerk/pull/232) to get Clerk working in babashka
+- [lein2deps](https://github.com/borkdude/lein2deps): lein to deps.edn converter
+- [awyeah-api](https://github.com/grzm/awyeah-api) by Michael Glaesemann v0.8.41 is now available! aws-api for Babashka. Aw yeah!
+- [bbssh](https://github.com/epiccastle/bbssh/releases/tag/v0.2.0) by Crispin Wellington, v0.2.0 released
+- [safely use rsync --archive --delete to backup a directory](https://gist.github.com/stelcodes/ddc8ff53de2192dca7d3fee1081ddb77) by Stel Abrego
+
+## [2022-09](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-10-01%20since%3A2022-09-01&src=typed_query&f=live)
+
+- Releases: [0.9.162 - 0.10.163](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
+- Introducing [bbin](https://radsmith.com/bbin): a tool to install babashka scripts on your system by Radford Smith
+- [bbssh](https://github.com/epiccastle/bbssh): Babashka pod for SSH support by [Epic Castle](https://github.com/epiccastle)
+- [Loom virtual threads are coming to babashka](https://twitter.com/borkdude/status/1572222344684531717)
+- [Tiny script to cycle through pulseaudio outputs (aka sinks)](https://gist.github.com/stelcodes/7d9136a5839b645b6cd5bc829a9fe541) by Stel Abrego
+- [Tetris in the console via pod-babashka-lantera](https://twitter.com/borkdude/status/1569351199404576770)
+- [org-mode gets support for babashka](https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=764642f55b7a9821acbabcfa1e2d354afab99be7)
+- [docs for combining babashka process with promesa](https://github.com/babashka/process#promesa)
+ [exoscale/interceptor](https://github.com/exoscale/interceptor) became babashka-compatible!
+- [Tutkain, socket REPL Sublime plugin, gets better support for babashka](https://twitter.com/borkdude/status/1568315151404924933)
+- [babashka tweepy](https://github.com/davclark/babashka-tweepy): kicking the tires on using the tweepy library from a babashka task by Dav Clark
+- [aoc helper](https://github.com/jjcomer/aoc-helper) by Josh Comer
+- [Dogfooding blambda part 5](https://jmglov.net/blog/2022-09-02-dogfooding-blambda-logs.html) by Josh Glover
+
+## [2022-08](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-09-01%20since%3A2022-08-01&src=typed_query&f=live)
+- It's babashka's third birthday on August 9th 2022!
+- [etaoin](https://github.com/clj-commons/etaoin), Pure Clojure Webdriver protocol implementation, is now babashka-compatible!
+- [xforms](https://github.com/cgrand/xforms) is now babashka-compatible!
+- [squint](https://github.com/squint-cljs/squint) and [cherry](https://github.com/squint-cljs/cherry) are CLJS-compilers that work with babashka!
+
+## [2022-07](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-08-01%20since%3A2022-07-01&src=typed_query&f=live)
+
+- Releases: [0.8.157 - 0.9.161](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Recursive document transformations with Pandoc and Clojure](https://play.teod.eu/document-transform-pandoc-clojure/) by Teodor Heggelund
- [Babashka toolbox](https://babashka.org/toolbox/): A categorised directory of libraries and tools for Babashka
- [Quickblog](https://github.com/borkdude/quickblog): Light-weight static blog engine for Clojure and babashka
@@ -23,7 +249,7 @@ Twitter.
- [Deleting AWS Glacier vaults with babashka](https://javahippie.net/clojure/2022/07/23/deleting-aws-glacier-vaults-with-babashka.html) by Tim Zöller
-## [2022-06](https://twitter.com/search?q=(%23babashka)%20until%3A2022-07-01%20since%3A2022-06-01&src=typed_query&f=live)
+## [2022-06](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-07-01%20since%3A2022-06-01&src=typed_query&f=live)
- Releases: [0.8.156](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [AWS wiki page](https://github.com/babashka/babashka/wiki/AWS)
@@ -37,7 +263,7 @@ Twitter.
- [Logseq bb tasks](https://github.com/logseq/bb-tasks): Reusable babashka tasks used by logseq team
- [Breakneck Babashka on K8s](Breakneck Babashka on K8s) by Heow Goodman
-## [2022-05](https://twitter.com/search?q=(%23babashka)%20until%3A2022-06-01%20since%3A2022-05-01&src=typed_query&f=live)
+## [2022-05](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-06-01%20since%3A2022-05-01&src=typed_query&f=live)
- Releases: [0.8.2](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Etaoin](https://github.com/clj-commons/etaoin) moved to clj-commons and now works with babashka as well.
@@ -47,7 +273,7 @@ Twitter.
- [Quickdoc](https://github.com/borkdude/quickdoc): (Quick and minimal API doc generation for Clojure
- [Awyeah-api](https://github.com/grzm/awyeah-api) - Cognitect's aws-api for babashka
-## [2022-04](https://twitter.com/search?q=(%23babashka)%20until%3A2022-05-01%20since%3A2022-04-01&src=typed_query&f=live)
+## [2022-04](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-05-01%20since%3A2022-04-01&src=typed_query&f=live)
- Releases: [0.8.0 - 0.8.1](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Babashka and Clojure](https://youtu.be/ZvOs5Ele6VE) by Rahul Dé at North Virginia Linux Users Group
@@ -55,7 +281,7 @@ Twitter.
- Control Chrome via devtools using [clj-chrome-devtools](https://github.com/tatut/clj-chrome-devtools/blob/master/bb.clj) which runs with bb!
- Use pods directly in `bb.edn`: [tweet](https://twitter.com/borkdude/status/1510995356229767172)
-## [2022-03](https://twitter.com/search?q=(%23babashka)%20until%3A2022-04-01%20since%3A2022-03-01&src=typed_query&f=live)
+## [2022-03](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-04-01%20since%3A2022-03-01&src=typed_query&f=live)
- Releases: [0.7.7 - 0.7.8](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Create a password manager with Clojure using Babashka, sqlite, honeysql and stash](https://youtu.be/jm0RXmyjRJ8) by Daniel Amber
@@ -65,7 +291,7 @@ Twitter.
- The [loom](https://github.com/aysylu/loom) library is now compatible [(tweet)](https://twitter.com/borkdude/status/1502237220811550723)
- The [at-at](https://github.com/overtone/at-at) library is now compatible
-## [2022-02](https://twitter.com/search?q=(%23babashka)%20until%3A2022-03-01%20since%3A2022-02-01&src=typed_query&f=live)
+## [2022-02](https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-03-01%20since%3A2022-02-01&src=typed_query&f=live)
- Releases: [0.7.5 - 0.7.6](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Spire is available as a babashka pod](https://twitter.com/epic_castle/status/1496784352256008194)
@@ -78,7 +304,7 @@ Twitter.
- [Apptemplate](https://github.com/redstarssystems/apptemplate): Application project template for Clojure featuring bb tasks
-## [2022-01](https://twitter.com/search?f=live&q=(%23babashka)%20until%3A2022-02-01%20since%3A2022-01-01&src=typed_query)
+## [2022-01](https://twitter.com/search?f=live&q=%28%23babashka%29%20until%3A2022-02-01%20since%3A2022-01-01&src=typed_query)
- Releases: [0.7.4](https://github.com/babashka/babashka/blob/master/CHANGELOG.md).
- [Babashka dev builds](https://github.com/babashka/babashka-dev-builds)
diff --git a/doc/projects.md b/doc/projects.md
index f27bbe9e..70f4a59e 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -66,6 +66,7 @@ The following libraries and projects are known to work with babashka.
- [Meander](#meander)
- [Schema](#schema)
- [Sluj](#sluj)
+ - [malli-cli](#malli-cli)
- [Pods](#pods)
- [Projects](#projects-1)
- [babashka-test-action](#babashka-test-action)
@@ -833,6 +834,10 @@ Clojure(Script) library for declarative data description and validation
Sluj is a very small library for converting strings of UTF-16 text to slugs. A slug is a piece of text that is URL safe.
+### [malli-cli](https://github.com/piotr-yuxuan/malli-cli)
+
+Configuration and CLI powertool with `metosin/malli`.
+
## Pods
[Babashka pods](https://github.com/babashka/babashka.pods) are programs that can
diff --git a/feature-httpkit-server/babashka/impl/httpkit_server.clj b/feature-httpkit-server/babashka/impl/httpkit_server.clj
index 42608208..9a087d88 100644
--- a/feature-httpkit-server/babashka/impl/httpkit_server.clj
+++ b/feature-httpkit-server/babashka/impl/httpkit_server.clj
@@ -15,4 +15,8 @@
'send-checked-websocket-handshake! (copy-var server/send-checked-websocket-handshake! sns)
'send-websocket-handshake! (copy-var server/send-websocket-handshake! sns)
'as-channel (copy-var server/as-channel sns)
- 'send! (copy-var server/send! sns)})
+ 'send! (copy-var server/send! sns)
+ 'with-channel (copy-var server/with-channel sns)
+ 'on-close (copy-var server/on-close sns)
+ 'close (copy-var server/close sns)}
+ )
diff --git a/feature-logging/babashka/impl/logging.clj b/feature-logging/babashka/impl/logging.clj
index 25e1221d..5eff64c2 100644
--- a/feature-logging/babashka/impl/logging.clj
+++ b/feature-logging/babashka/impl/logging.clj
@@ -13,56 +13,78 @@
(defn- fline [and-form] (:line (meta and-form)))
+(defonce callsite-counter
+ (enc/counter))
+
(defmacro log! ; Public wrapper around `-log!`
- "Core low-level log macro. Useful for tooling, etc.
- * `level` - must eval to a valid logging level
- * `msg-type` - must eval to e/o #{:p :f nil}
- * `opts` - ks e/o #{:config :?err :?ns-str :?file :?line :?base-data :spying?}
- Supports compile-time elision when compile-time const vals
- provided for `level` and/or `?ns-str`."
- [level msg-type args & [opts]]
- (have [:or nil? sequential?] args) ; To allow -> (delay [~@args])
- (let [{:keys [?ns-str] :or {?ns-str (str @sci/ns)}} opts]
- ;; level, ns may/not be compile-time consts:
- (when-not (timbre/-elide? level ?ns-str)
- (let [{:keys [config ?err ?file ?line ?base-data spying?]
- :or {config 'taoensso.timbre/*config*
- ?err :auto ; => Extract as err-type v0
- ?file @sci/file
- ;; NB waiting on CLJ-865:
- ?line (fline &form)}} opts
+ "Core low-level log macro. Useful for tooling/library authors, etc.
- ?file (when (not= ?file "NO_SOURCE_PATH") ?file)
+ * `level` - must eval to a valid logging level
+ * `msg-type` - must eval to e/o #{:p :f nil}
+ * `args` - arguments seq (ideally vec) for logging call
+ * `opts` - ks e/o #{:config ?err ?base-data spying?
+ :?ns-str :?file :?line :?column}
- ;; Identifies this particular macro expansion; note that this'll
- ;; be fixed for any fns wrapping `log!` (notably `tools.logging`,
- ;; `slf4j-timbre`, etc.):
- callsite-id
- (hash [level msg-type args ; Unevaluated args (arg forms)
- ?ns-str ?file ?line (rand)])]
+ Supports compile-time elision when compile-time const vals
+ provided for `level` and/or `?ns-str`.
- `(taoensso.timbre/-log! ~config ~level ~?ns-str ~?file ~?line ~msg-type ~?err
- (delay [~@args]) ~?base-data ~callsite-id ~spying?)))))
+ Logging wrapper examples:
+
+ (defn log-wrapper-fn [& args] (timbre/log! :info :p args))
+ (defmacro log-wrapper-macro [& args] (timbre/keep-callsite `(timbre/log! :info :p ~args)))"
+
+ ([{:as opts
+ :keys [loc level msg-type args vargs
+ config ?err ?base-data spying?]
+ :or
+ {config 'taoensso.timbre/*config*
+ ?err :auto}}]
+
+ (have [:or nil? sequential? symbol?] args)
+ (let [callsite-id (callsite-counter)
+ {:keys [line column]} (merge (meta &form) loc)
+ {:keys [ns file line column]} {:ns @sci/ns :file @sci/file :line line :column column}
+ ns (or (get opts :?ns-str) ns)
+ file (or (get opts :?file) file)
+ line (or (get opts :?line) line)
+ column (or (get opts :?column) column)
+
+ elide? (and #_(enc/const-forms? level ns) (timbre/-elide? level ns))]
+
+ (when-not elide?
+ (let [vargs-form
+ (or vargs
+ (if (symbol? args)
+ `(taoensso.timbre/-ensure-vec ~args)
+ `[ ~@args]))]
+
+ ;; Note pre-resolved expansion
+ `(taoensso.timbre/-log! ~config ~level ~ns ~file ~line ~column ~msg-type ~?err
+ (delay ~vargs-form) ~?base-data ~callsite-id ~spying?)))))
+
+ ([level msg-type args & [opts]]
+ (let [{:keys [line column]} (merge (meta &form))
+ {:keys [ns file line column]} {:ns @sci/ns :file @sci/file :line line :column column}
+ loc {:ns ns :file file :line line :column column}
+ opts (assoc (conj {:loc loc} opts)
+ :level level, :msg-type msg-type, :args args)]
+ `(taoensso.timbre/log! ~opts))))
(defn make-ns [ns sci-ns ks]
(reduce (fn [ns-map [var-name var]]
(let [m (meta var)
- no-doc (:no-doc m)
doc (:doc m)
arglists (:arglists m)]
- (if no-doc ns-map
- (assoc ns-map var-name
- (sci/new-var (symbol var-name) @var
- (cond-> {:ns sci-ns
- :name (:name m)}
- (:macro m) (assoc :macro true)
- doc (assoc :doc doc)
- arglists (assoc :arglists arglists)))))))
+ (assoc ns-map var-name
+ (sci/new-var (symbol var-name) @var
+ (cond-> {:ns sci-ns
+ :name (:name m)}
+ (:macro m) (assoc :macro true)
+ doc (assoc :doc doc)
+ arglists (assoc :arglists arglists))))))
{}
(select-keys (ns-publics ns) ks)))
-(def atomic-println @#'appenders/atomic-println)
-
(defn println-appender
"Returns a simple `println` appender for Clojure/Script.
Use with ClojureScript requires that `cljs.core/*print-fn*` be set.
@@ -92,7 +114,7 @@
:*err* @sci/err
stream)]
(binding [*out* stream]
- (atomic-println (force output_)))))}))
+ (enc/println-atomic (force output_)))))}))
(def default-config (assoc-in timbre/*config* [:appenders :println]
(println-appender {:stream :auto})))
@@ -127,7 +149,13 @@
'merge-config! (sci/copy-var merge-config! tns)
'set-level! (sci/copy-var set-level! tns)
'println-appender (sci/copy-var println-appender tns)
- '-log-and-rethrow-errors (sci/copy-var -log-and-rethrow-errors tns)))
+ '-log-and-rethrow-errors (sci/copy-var -log-and-rethrow-errors tns)
+ '-ensure-vec (sci/copy-var enc/ensure-vec tns)))
+
+(def timbre-appenders-namespace
+ (let [tan (sci/create-ns 'taoensso.timbre.appenders.core nil)]
+ {'println-appender (sci/copy-var println-appender tan)
+ 'spit-appender (sci/copy-var #_:clj-kondo/ignore timbre/spit-appender tan)}))
;;;; clojure.tools.logging
diff --git a/feature-selmer/babashka/impl/selmer.clj b/feature-selmer/babashka/impl/selmer.clj
index 32aeba3e..155c8bed 100644
--- a/feature-selmer/babashka/impl/selmer.clj
+++ b/feature-selmer/babashka/impl/selmer.clj
@@ -4,6 +4,7 @@
[babashka.impl.common :refer [ctx]]
[sci.core :as sci]
[selmer.filters :as filters]
+ [selmer.filter-parser :as fp]
[selmer.parser]
[selmer.tags :as tags]
[selmer.util :as util]
@@ -83,12 +84,31 @@
(apply merge)
(selmer.parser/render ~s)))
+(defn resolve-arg
+ "Resolves an arg as passed to an add-tag! handler using the provided
+ context-map.
+
+ A custom tag handler will receive a seq of args as its first argument.
+ With this function, you can selectively resolve one or more of those args
+ so that if they contain literals, the literal value is returned, and if they
+ contain templates of any sort, which can itself have variables, filters or
+ tags in it, they will be returned resolved, applied and rendered.
+
+ Example:
+ (resolve-arg {{header-name|upper}} {:header-name \"My Page\"})
+ => \"MY PAGE\""
+ [arg context-map]
+ (if (fp/literal? arg)
+ (fp/parse-literal arg)
+ (render arg context-map)))
+
(def selmer-parser-namespace
(-> selmer-parser-ns
(assoc 'render-file (sci/copy-var render-file spns)
'render (sci/copy-var render spns)
'render-template (sci/copy-var render-template spns)
'resolve-var-from-kw (sci/copy-var resolve-var-from-kw spns)
+ 'resolve-arg (sci/copy-var resolve-arg spns )
'<< (sci/copy-var << spns))))
(def stns (sci/create-ns 'selmer.tags nil))
@@ -105,7 +125,9 @@
(def selmer-filters-namespace
{'add-filter! (sci/copy-var filters/add-filter! sfns)
- 'remove-filter! (sci/copy-var filters/remove-filter! sfns)})
+ 'remove-filter! (sci/copy-var filters/remove-filter! sfns)
+ 'get-filter (sci/copy-var filters/get-filter sfns)
+ 'filters (sci/copy-var filters/filters sfns)})
(defn turn-off-escaping! []
(sci/alter-var-root escape-variables (constantly false)))
diff --git a/feature-yaml/babashka/impl/ordered.clj b/feature-yaml/babashka/impl/ordered.clj
index a0c87a97..bdb9c7b3 100644
--- a/feature-yaml/babashka/impl/ordered.clj
+++ b/feature-yaml/babashka/impl/ordered.clj
@@ -1,9 +1,14 @@
(ns babashka.impl.ordered
{:no-doc true}
(:require [flatland.ordered.map :as omap]
+ [flatland.ordered.set :as oset]
[sci.core :as sci]))
(def omap-ns (sci/create-ns 'flatland.ordered.map nil))
+(def oset-ns (sci/create-ns 'flatland.ordered.set nil))
(def ordered-map-ns
{'ordered-map (sci/copy-var omap/ordered-map omap-ns)})
+
+(def ordered-set-ns
+ {'ordered-set (sci/copy-var oset/ordered-set oset-ns)})
diff --git a/fs b/fs
index d3226ccc..8658cab4 160000
--- a/fs
+++ b/fs
@@ -1 +1 @@
-Subproject commit d3226cccd9898eba5adb50dfcc30a7223ff5c8cc
+Subproject commit 8658cab4981158dfd439b55b5932a276c4b65bf2
diff --git a/reify/.dir-locals.el b/impl-java/.dir-locals.el
similarity index 100%
rename from reify/.dir-locals.el
rename to impl-java/.dir-locals.el
diff --git a/reify/bb.edn b/impl-java/bb.edn
similarity index 100%
rename from reify/bb.edn
rename to impl-java/bb.edn
diff --git a/reify/build.clj b/impl-java/build.clj
similarity index 84%
rename from reify/build.clj
rename to impl-java/build.clj
index c0493917..b2688a9c 100644
--- a/reify/build.clj
+++ b/impl-java/build.clj
@@ -2,8 +2,8 @@
(:require [build.reify2 :as reify2]
[clojure.tools.build.api :as b]))
-(def lib 'org.babashka/babashka.impl.reify)
-(def version "0.1.3")
+(def lib 'org.babashka/babashka.impl.java)
+(def version "0.1.8")
(def class-dir "target/classes")
(def basis (b/create-basis {:project "deps.edn"}))
(def jar-file (format "target/%s-%s.jar" (name lib) version))
@@ -14,7 +14,13 @@
(defn gen-classes [_]
(reify2/gen-classes nil))
+(defn compile-java [_]
+ (b/javac {:src-dirs ["src-java"]
+ :class-dir class-dir
+ :basis basis}))
+
(defn jar [_]
+ (compile-java nil)
(gen-classes nil)
(b/write-pom {:class-dir class-dir
:lib lib
diff --git a/reify/build/reify2.clj b/impl-java/build/reify2.clj
similarity index 100%
rename from reify/build/reify2.clj
rename to impl-java/build/reify2.clj
diff --git a/reify/deps.edn b/impl-java/deps.edn
similarity index 100%
rename from reify/deps.edn
rename to impl-java/deps.edn
diff --git a/impl-java/src-java/babashka/impl/URLClassLoader.java b/impl-java/src-java/babashka/impl/URLClassLoader.java
new file mode 100644
index 00000000..9416f2b9
--- /dev/null
+++ b/impl-java/src-java/babashka/impl/URLClassLoader.java
@@ -0,0 +1,94 @@
+// This file is mostly a workaround for https://github.com/oracle/graal/issues/1956
+
+package babashka.impl;
+
+import java.util.WeakHashMap;
+import java.io.*;
+import java.util.Objects;
+import java.net.*;
+import java.util.jar.*;
+
+public class URLClassLoader extends java.net.URLClassLoader implements Closeable {
+
+ private WeakHashMap
+ closeables = new WeakHashMap<>();
+
+ public URLClassLoader(java.net.URL[] urls) {
+ super(urls);
+ }
+
+ public URLClassLoader(java.net.URL[] urls, java.net.URLClassLoader parent) {
+ super(urls, parent);
+ }
+
+ public void _addURL(java.net.URL url) {
+ super.addURL(url);
+ }
+
+ // calling super.getResource() returned nil in native-image
+ public java.net.URL getResource(String name) {
+ return findResource(name);
+ }
+
+ // calling super.getResourceAsStream() returned nil in native-image
+ public InputStream getResourceAsStream(String name) {
+ Objects.requireNonNull(name);
+ URL url = getResource(name);
+ try {
+ if (url == null) {
+ return null;
+ }
+ URLConnection urlc = url.openConnection();
+ InputStream is = urlc.getInputStream();
+ if (urlc instanceof JarURLConnection) {
+ JarFile jar = ((JarURLConnection)urlc).getJarFile();
+ synchronized (closeables) {
+ if (!closeables.containsKey(jar)) {
+ closeables.put(jar, null);
+ }
+ }
+ } else {
+ synchronized (closeables) {
+ closeables.put(is, null);
+ }
+ }
+ return is;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ public java.util.Enumeration getResources(String name) throws java.io.IOException {
+ return findResources(name);
+ }
+
+ public void close() throws IOException {
+ super.close();
+
+ java.util.List errors = new java.util.ArrayList();
+
+ synchronized (closeables) {
+ java.util.Set keys = closeables.keySet();
+ for (Closeable c : keys) {
+ try {
+ c.close();
+ } catch (IOException ex) {
+ errors.add(ex);
+ }
+ }
+ closeables.clear();
+ }
+
+ if (errors.isEmpty()) {
+ return;
+ }
+
+ IOException firstEx = errors.remove(0);
+
+ for (IOException error: errors) {
+ firstEx.addSuppressed(error);
+ }
+ throw firstEx;
+ }
+
+}
diff --git a/reify/src/babashka/impl/reify2.clj b/impl-java/src/babashka/impl/reify2.clj
similarity index 100%
rename from reify/src/babashka/impl/reify2.clj
rename to impl-java/src/babashka/impl/reify2.clj
diff --git a/reify/src/babashka/impl/reify2/interfaces.clj b/impl-java/src/babashka/impl/reify2/interfaces.clj
similarity index 87%
rename from reify/src/babashka/impl/reify2/interfaces.clj
rename to impl-java/src/babashka/impl/reify2/interfaces.clj
index a94feec3..da99f041 100644
--- a/reify/src/babashka/impl/reify2/interfaces.clj
+++ b/impl-java/src/babashka/impl/reify2/interfaces.clj
@@ -31,4 +31,7 @@
java.lang.Comparable
javax.net.ssl.X509TrustManager
clojure.lang.LispReader$Resolver
- sun.misc.SignalHandler])
+ sun.misc.SignalHandler
+ java.util.concurrent.ThreadFactory
+ java.lang.Thread$UncaughtExceptionHandler
+ java.util.concurrent.Callable])
diff --git a/install b/install
index 349405b0..0e9796cf 100755
--- a/install
+++ b/install
@@ -96,7 +96,11 @@ IFS='.' read -ra VER <<< "${version//-SNAPSHOT/}"
vernum=$(printf "%03d%03d%03d" "${VER[0]}" "${VER[1]}" "${VER[2]}")
case "$(uname -m)" in
- aarch64) arch=aarch64;;
+ aarch64) arch=aarch64
+ if [[ "$platform" == "linux" ]]; then
+ static_binary="true"
+ fi
+ ;;
arm64) if [[ 10#$vernum -le 10#000008002 ]]; then
arch="amd64"
else
diff --git a/pods b/pods
index decf7910..717cef7a 160000
--- a/pods
+++ b/pods
@@ -1 +1 @@
-Subproject commit decf791000081ca9e6d2fbea9f20a0aa3fae902e
+Subproject commit 717cef7af5cb1c1b091bd10e012b2e71b7b8b9bc
diff --git a/process b/process
index 90e4cf0b..7b025841 160000
--- a/process
+++ b/process
@@ -1 +1 @@
-Subproject commit 90e4cf0b0cc7856f8c39591c3350cdf156d11042
+Subproject commit 7b02584145992832c4a50f4f571b009ff093585d
diff --git a/project.clj b/project.clj
index f5794d71..4814baeb 100644
--- a/project.clj
+++ b/project.clj
@@ -11,35 +11,40 @@
"babashka.core/src"
"babashka.nrepl/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources"
- "reify/src"]
+ "impl-java/src"]
;; for debugging Reflector.java code:
;; :java-source-paths ["sci/reflector/src-java"]
:java-source-paths ["src-java"]
:resource-paths ["resources" "sci/resources"]
- :test-selectors {:default (complement :windows-only)
- :windows (complement :skip-windows)}
- :dependencies [[org.clojure/clojure "1.11.1"]
- [borkdude/edamame "1.0.16"]
+ :test-selectors {:default (complement (some-fn :windows-only :flaky))
+ :windows (complement (some-fn :skip-windows :flaky))
+ :non-flaky (complement :flaky)
+ :flaky :flaky}
+ :jvm-opts ["--enable-preview"]
+ :dependencies [[org.clojure/clojure "1.11.2"]
+ [borkdude/edamame "1.4.24"]
[borkdude/graal.locking "0.0.2"]
[org.clojure/tools.cli "1.0.214"]
- [cheshire "5.11.0"]
+ [cheshire "5.13.0"]
[nrepl/bencode "1.1.0"]
[borkdude/sci.impl.reflector "0.0.1"]
[org.babashka/sci.impl.types "0.0.2"]
- [org.babashka/babashka.impl.reify "0.1.3"]
+ [org.babashka/babashka.impl.java "0.1.8"]
[org.clojure/core.async "1.6.673"]
[org.clojure/test.check "1.1.1"]
[com.github.clj-easy/graal-build-time "0.1.0"]
- [rewrite-clj/rewrite-clj "1.1.45"]
+ [rewrite-clj/rewrite-clj "1.1.47"]
[insn/insn "0.5.2"]
- [org.babashka/cli "0.6.41"]]
+ [org.babashka/cli "0.8.59"]
+ [org.babashka/http-client "0.4.18"]]
:plugins [[org.kipz/lein-meta-bom "0.1.1"]]
:metabom {:jar-name "metabom.jar"}
:profiles {:feature/xml {:source-paths ["feature-xml"]
:dependencies [[org.clojure/data.xml "0.2.0-alpha8"]]}
:feature/yaml {:source-paths ["feature-yaml"]
- :dependencies [[clj-commons/clj-yaml "0.7.169"
- #_#_clj-commons/clj-yaml "0.7.110"]]}
+ :dependencies [[clj-commons/clj-yaml "1.0.27"
+ :exclusions [org.flatland/ordered]#_#_clj-commons/clj-yaml "0.7.110"]
+ [org.flatland/ordered "1.15.12"]]}
:feature/jdbc {:source-paths ["feature-jdbc"]
:dependencies [[seancorfield/next.jdbc "1.1.610"]]}
:feature/sqlite [:feature/jdbc {:dependencies [[org.xerial/sqlite-jdbc "3.36.0.3"]]}]
@@ -50,25 +55,25 @@
:feature/csv {:source-paths ["feature-csv"]
:dependencies [[org.clojure/data.csv "1.0.0"]]}
:feature/transit {:source-paths ["feature-transit"]
- :dependencies [[com.cognitect/transit-clj "1.0.329"]]}
+ :dependencies [[com.cognitect/transit-clj "1.0.333"]]}
:feature/datascript {:source-paths ["feature-datascript"]
:dependencies [[datascript "1.3.10"]]}
:feature/httpkit-client {:source-paths ["feature-httpkit-client"]
- :dependencies [[http-kit "2.6.0-RC1"]]}
+ :dependencies [[http-kit "2.8.0-RC1"]]}
:feature/httpkit-server {:source-paths ["feature-httpkit-server"]
- :dependencies [[http-kit "2.6.0-RC1"]]}
+ :dependencies [[http-kit "2.8.0-RC1"]]}
:feature/lanterna {:source-paths ["feature-lanterna"]
:dependencies [[babashka/clojure-lanterna "0.9.8-SNAPSHOT"]]}
:feature/core-match {:source-paths ["feature-core-match"]
:dependencies [[org.clojure/core.match "1.0.0"]]}
:feature/hiccup {:source-paths ["feature-hiccup"]
- :dependencies [[hiccup/hiccup "2.0.0-alpha2"]]}
+ :dependencies [[hiccup/hiccup "2.0.0-RC1"]]}
:feature/test-check {:source-paths ["feature-test-check"]}
:feature/spec-alpha {:source-paths ["feature-spec-alpha"]}
:feature/selmer {:source-paths ["feature-selmer"]
- :dependencies [[selmer/selmer "1.12.50"]]}
+ :dependencies [[selmer/selmer "1.12.59"]]}
:feature/logging {:source-paths ["feature-logging"]
- :dependencies [[com.taoensso/timbre "6.0.1"]
+ :dependencies [[com.taoensso/timbre "6.5.0"]
[org.clojure/tools.logging "1.1.0"]]}
:feature/priority-map {:source-paths ["feature-priority-map"]
:dependencies [[org.clojure/data.priority-map "1.1.0"]]}
@@ -92,7 +97,8 @@
:feature/logging
:feature/priority-map
:feature/rrb-vector
- {:dependencies [[com.clojure-goes-fast/clj-async-profiler "0.5.0"]
+ {:dependencies [[borkdude/rewrite-edn "0.4.6"]
+ [com.clojure-goes-fast/clj-async-profiler "0.5.0"]
[com.opentable.components/otj-pg-embedded "0.13.3"]
[nubank/matcher-combinators "3.6.0"]]}]
:uberjar {:global-vars {*assert* false}
diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION
index 6aafafcc..d6778277 100644
--- a/resources/BABASHKA_RELEASED_VERSION
+++ b/resources/BABASHKA_RELEASED_VERSION
@@ -1 +1 @@
-1.0.168
\ No newline at end of file
+1.3.190
\ No newline at end of file
diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION
index a3361b37..3a1ea432 100644
--- a/resources/BABASHKA_VERSION
+++ b/resources/BABASHKA_VERSION
@@ -1 +1 @@
-1.0.169-SNAPSHOT
\ No newline at end of file
+1.3.191-SNAPSHOT
\ No newline at end of file
diff --git a/resources/META-INF/babashka/deps.edn b/resources/META-INF/babashka/deps.edn
index 692d7724..663c383b 100644
--- a/resources/META-INF/babashka/deps.edn
+++ b/resources/META-INF/babashka/deps.edn
@@ -17,10 +17,10 @@
"depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources"
"resources" "sci/resources"
- "reify/src"],
- :deps {org.clojure/clojure {:mvn/version "1.11.1"},
+ "impl-java/src"],
+ :deps {org.clojure/clojure {:mvn/version "1.11.2"},
org.babashka/sci {:local/root "sci"}
- org.babashka/babashka.impl.reify {:mvn/version "0.1.3"}
+ org.babashka/babashka.impl.java {:mvn/version "0.1.8"}
org.babashka/sci.impl.types {:mvn/version "0.0.2"}
babashka/babashka.curl {:local/root "babashka.curl"}
babashka/fs {:local/root "fs"}
@@ -29,28 +29,30 @@
org.clojure/core.async {:mvn/version "1.6.673"},
org.clojure/tools.cli {:mvn/version "1.0.214"},
org.clojure/data.csv {:mvn/version "1.0.0"},
- cheshire/cheshire {:mvn/version "5.11.0"}
+ cheshire/cheshire {:mvn/version "5.13.0"}
org.clojure/data.xml {:mvn/version "0.2.0-alpha8"}
- clj-commons/clj-yaml {:mvn/version "0.7.169"}
- com.cognitect/transit-clj {:mvn/version "1.0.329"}
+ clj-commons/clj-yaml {:mvn/version "1.0.27"}
+ com.cognitect/transit-clj {:mvn/version "1.0.333"}
org.clojure/test.check {:mvn/version "1.1.1"}
nrepl/bencode {:mvn/version "1.1.0"}
seancorfield/next.jdbc {:mvn/version "1.1.610"}
org.postgresql/postgresql {:mvn/version "42.2.18"}
org.hsqldb/hsqldb {:mvn/version "2.5.1"}
datascript/datascript {:mvn/version "1.0.1"}
- http-kit/http-kit {:mvn/version "2.6.0-RC1"}
+ http-kit/http-kit {:mvn/version "2.8.0-RC1"}
babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"}
org.clojure/core.match {:mvn/version "1.0.0"}
- hiccup/hiccup {:mvn/version "2.0.0-alpha2"}
- rewrite-clj/rewrite-clj {:mvn/version "1.1.45"}
- selmer/selmer {:mvn/version "1.12.50"}
- com.taoensso/timbre {:mvn/version "6.0.1"}
+ hiccup/hiccup {:mvn/version "2.0.0-RC1"}
+ rewrite-clj/rewrite-clj {:mvn/version "1.1.47"}
+ selmer/selmer {:mvn/version "1.12.59"}
+ com.taoensso/timbre {:mvn/version "6.5.0"}
org.clojure/tools.logging {:mvn/version "1.1.0"}
org.clojure/data.priority-map {:mvn/version "1.1.0"}
insn/insn {:mvn/version "0.5.2"}
org.clojure/core.rrb-vector {:mvn/version "0.1.2"}
- org.babashka/cli {:mvn/version "0.6.41"}}
+ org.babashka/cli {:mvn/version "0.8.58"}
+ org.babashka/http-client {:mvn/version "0.4.16"}
+ org.flatland/ordered {:mvn/version "1.15.12"}}
:aliases {:babashka/dev
{:main-opts ["-m" "babashka.main"]}
:profile
@@ -64,7 +66,7 @@
{:extra-paths ["process/src" "process/test" "test-resources/lib_tests"]
:extra-deps {org.clj-commons/clj-http-lite {:mvn/version "0.4.392"}
#_#_org.babashka/spec.alpha {:git/url "https://github.com/babashka/spec.alpha"
- :sha "0dec1f88cbde74a0470b454396f09a03adb4ae39"}
+ :sha "0dec1f88cbde74a0470b454396f09a03adb4ae39"}
lambdaisland/regal {:mvn/version "0.0.143"}
cprop/cprop {:mvn/version "0.1.16"}
comb/comb {:mvn/version "0.1.1"}
@@ -106,7 +108,7 @@
exoscale/coax {:mvn/version "1.0.0-alpha14"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
expound/expound {:mvn/version "0.8.10"}
- integrant/integrant {:mvn/version "0.8.0"}
+ integrant/integrant {:git/url "https://github.com/weavejester/integrant", :git/sha "a9fd7c02bd7201f36344b47142badc3c3ef22f88"}
com.stuartsierra/dependency {:mvn/version "1.0.0"}
listora/again {:mvn/version "1.0.0"}
org.clojure/tools.gitlibs {:mvn/version "2.4.172"}
@@ -165,7 +167,12 @@
:git/sha "1a29775a3d286f9f6fe3f979c78b6e2bf298d5ba"}
com.github.rawleyfowler/sluj {:git/url "https://github.com/rawleyfowler/sluj"
:git/sha "4a92e772b4e07bf127423448d4140748b5782198"
- :deps/manifest :deps}}
+ :deps/manifest :deps}
+ net.cgrand/xforms {:git/url "https://github.com/cgrand/xforms"
+ :git/sha "550dbc150a79c6ecc148d8a7e260e10bc36321c6"
+ :deps/manifest :deps}
+ prismatic/plumbing {:git/url "https://github.com/plumatic/plumbing",
+ :git/sha "424bc704f2db422de34269c139a5494314b3a43b"}}
:classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil}}
:clj-nvd
diff --git a/resources/META-INF/native-image/babashka/babashka/native-image.properties b/resources/META-INF/native-image/babashka/babashka/native-image.properties
index 2e6e0571..ea2ccd7e 100644
--- a/resources/META-INF/native-image/babashka/babashka/native-image.properties
+++ b/resources/META-INF/native-image/babashka/babashka/native-image.properties
@@ -7,7 +7,7 @@ Args=-H:+ReportExceptionStackTraces \
-H:IncludeResources=src/babashka/.* \
-H:IncludeResources=SCI_VERSION \
-H:Log=registerResource:3 \
- -H:EnableURLProtocols=http,https,jar \
+ --enable-url-protocols=http,https,jar,unix \
--enable-all-security-services \
-H:+JNI \
--no-server \
@@ -26,4 +26,31 @@ Args=-H:+ReportExceptionStackTraces \
-H:ServiceLoaderFeatureExcludeServices=javax.sound.midi.spi.SoundbankReader \
-H:ServiceLoaderFeatureExcludeServices=javax.sound.midi.spi.MidiFileWriter \
-H:ServiceLoaderFeatureExcludeServices=java.net.ContentHandlerFactory \
- -H:ServiceLoaderFeatureExcludeServices=java.nio.charset.spi.CharsetProvider
+ -H:ServiceLoaderFeatureExcludeServices=java.nio.charset.spi.CharsetProvider \
+ -EBABASHKA_STATIC \
+ -EBABASHKA_MUSL \
+ -EBABASHKA_FEATURE_YAML \
+ -EBABASHKA_FEATURE_XML \
+ -EBABASHKA_FEATURE_CSV \
+ -EBABASHKA_FEATURE_TRANSIT \
+ -EBABASHKA_FEATURE_JAVA_TIME \
+ -EBABASHKA_FEATURE_JAVA_NET_HTTP \
+ -EBABASHKA_FEATURE_JAVA_NIO \
+ -EBABASHKA_FEATURE_HTTPKIT_CLIENT \
+ -EBABASHKA_FEATURE_HTTPKIT_SERVER \
+ -EBABASHKA_FEATURE_CORE_MATCH \
+ -EBABASHKA_FEATURE_HICCUP \
+ -EBABASHKA_FEATURE_TEST_CHECK \
+ -EBABASHKA_FEATURE_SELMER \
+ -EBABASHKA_FEATURE_LOGGING \
+ -EBABASHKA_FEATURE_PRIORITY_MAP \
+ -EBABASHKA_FEATURE_JDBC \
+ -EBABASHKA_FEATURE_SQLITE \
+ -EBABASHKA_FEATURE_POSTGRESQL \
+ -EBABASHKA_FEATURE_ORACLEDB \
+ -EBABASHKA_FEATURE_HSQLDB \
+ -EBABASHKA_FEATURE_DATASCRIPT \
+ -EBABASHKA_FEATURE_LANTERNA \
+ -EBABASHKA_FEATURE_SPEC_ALPHA \
+ -EBABASHKA_FEATURE_RRB_VECTOR \
+ -EBABASHKA_REQUIRE_SCAN
diff --git a/resources/UrlClassLoaderSubstitutions.java b/resources/UrlClassLoaderSubstitutions.java
new file mode 100644
index 00000000..53bb1a32
--- /dev/null
+++ b/resources/UrlClassLoaderSubstitutions.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessControlContext;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.WeakHashMap;
+
+import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.RecomputeFieldValue;
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+
+@TargetClass(URLClassLoader.class)
+@SuppressWarnings({"unused", "static-method"})
+final class Target_java_net_URLClassLoader {
+ @Alias//
+ @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = WeakHashMap.class)//
+ private WeakHashMap closeables;
+
+ @Substitute
+ public InputStream getResourceAsStream(String name) throws IOException {
+ System.out.println("getResource");
+ return null;
+ // return Resources.createInputStream(name);
+ }
+}
diff --git a/resources/src/babashka/clojure/spec/alpha.clj b/resources/src/babashka/clojure/spec/alpha.clj
index 9b9772d3..b24f5688 100644
--- a/resources/src/babashka/clojure/spec/alpha.clj
+++ b/resources/src/babashka/clojure/spec/alpha.clj
@@ -322,10 +322,7 @@
"Returns a symbol from a symbol or var"
[x]
(if (var? x)
- (let [m (meta x)
- n (:name m)
- ns (:ns m)]
- (symbol (str ns) (str n)))
+ (symbol x)
x))
(defn- unfn [expr]
@@ -339,10 +336,7 @@
(defn- res [form]
(cond
(keyword? form) form
- (symbol? form) (cond
- (= 'fn form) 'clojure.core/fn ;; make tests pass, fn is not a macro in SCI
- (= 'not form) 'clojure.core/not ;; make tests pass, not is not a macro in SCI
- :else (c/or (-> form resolve ->sym) form))
+ (symbol? form) (c/or (-> form resolve ->sym) form)
(sequential? form) (walk/postwalk #(if (symbol? %) (res %) %) (unfn form))
:else form))
diff --git a/sci b/sci
index 92a07126..bf6a0f1e 160000
--- a/sci
+++ b/sci
@@ -1 +1 @@
-Subproject commit 92a071269f1a4e3f4fda262b33b47ec827be3d4e
+Subproject commit bf6a0f1e00313a902c62c59e440266612725b926
diff --git a/script/built_in.clj b/script/built_in.clj
index 743b2b02..346acca3 100755
--- a/script/built_in.clj
+++ b/script/built_in.clj
@@ -9,7 +9,8 @@
(let [tmp-dir (fs/file tmp-dir)]
(shell {:dir tmp-dir} "git clone https://github.com/babashka/spec.alpha")
(let [spec-dir (fs/file tmp-dir "spec.alpha")]
- (shell {:dir spec-dir} "git reset 1d9df099be4fbfd30b9b903642ad376373c16298 --hard")
- (fs/copy-tree (fs/file spec-dir "src" "main" "clojure") (fs/file "resources" "src" "babashka")))))
+ (shell {:dir spec-dir} "git reset 951b49b8c173244e66443b8188e3ff928a0a71e7 --hard")
+ (fs/copy-tree (fs/file spec-dir "src" "main" "clojure") (fs/file "resources" "src" "babashka")
+ {:replace-existing true}))))
diff --git a/script/bump_graal_version.clj b/script/bump_graal_version.clj
index 191c8e01..415d5896 100755
--- a/script/bump_graal_version.clj
+++ b/script/bump_graal_version.clj
@@ -11,7 +11,7 @@
;; GraalVM Community Edition 19.3.2 based on OpenJDK 8u252
;; GraalVM Community Edition 19.3.2 based on OpenJDK 11.0.7
;;
-;; Currently we use GraalVM java11-20.1.0
+;; Currently we use GraalVM java19-20.1.0
(ns bump-graal-version
(:require [clojure.string :as str]
@@ -31,8 +31,8 @@
""
"./bump_graal_version.clj -g 19.3.2 (the new version)"
"or"
- "./bump_graal_version.clj -g 19.3.2 --java java11"
- "(for GraalVM java11-19.3.2)"
+ "./bump_graal_version.clj -g 19.3.2 --java java19"
+ "(for GraalVM java19-19.3.2)"
""]
(str/join \newline))))
@@ -54,8 +54,8 @@
;; OR
;;
;; We could have them as environment variables
-(def current-graal-version "22.3.0")
-(def current-java-version "java11")
+(def current-graal-version "22.3.1")
+(def current-java-version "java19")
(def cl-options
[["-g" "--graal VERSION" "graal version"]
diff --git a/script/check_glibc.sh b/script/check_glibc.sh
new file mode 100755
index 00000000..36a3bf4a
--- /dev/null
+++ b/script/check_glibc.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+function ver_lte() {
+ printf '%s\n%s' "$1" "$2" | sort -C -V
+}
+
+max_glibc_version="2.31"
+current_glibc_version=$(ldd --version | head -1 | awk '{print $4}' | cut -d "-" -f 1)
+
+function bail() {
+ echo "glibc greater than max version ${max_glibc_version}: ${current_glibc_version}"
+ exit 1
+}
+
+ver_lte "${current_glibc_version}" "${max_glibc_version}" || bail
diff --git a/script/compile b/script/compile
index 17b7dc76..04c3c1f7 100755
--- a/script/compile
+++ b/script/compile
@@ -26,17 +26,6 @@ fi
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH
-rm -rf resources/*.class
-# SVM_JAR=$(find -L "$GRAALVM_HOME" | grep svm.jar)
-# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffCoreServicesDependencies.java
-# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffSunAwtWwwContentAudioAiff.java
-# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffMisc.java
-if [ -z "$BABASHKA_JAR" ]; then
- lein with-profiles +reflection,+native-image "do" run
- lein "do" clean, uberjar, metabom
- BABASHKA_JAR=${BABASHKA_JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"}
-fi
-
# because script/test cleans target during ci before the jar can we saved
cp target/metabom.jar .
@@ -54,8 +43,12 @@ args=("-jar" "$BABASHKA_JAR"
"--verbose"
"--no-fallback"
"--native-image-info"
+ "--install-exit-handlers"
# --trace-class-initialization=jdk.internal.net.http.common.DebugLogger,jdk.internal.net.http.websocket.WebSocketImpl,jdk.internal.net.http.common.Utils
- "$BABASHKA_XMX")
+ "$BABASHKA_XMX"
+ "--enable-preview"
+ "-march=compatibility" # necessary for compatibility with older machines, e.g. see https://github.com/borkdude/deps.clj/actions/runs/6337277754/job/17212028399
+ "-O1")
BABASHKA_STATIC=${BABASHKA_STATIC:-}
BABASHKA_MUSL=${BABASHKA_MUSL:-}
@@ -113,4 +106,4 @@ then
export BABASHKA_FEATURE_PRIORITY_MAP="${BABASHKA_FEATURE_PRIORITY_MAP:-false}"
fi
-"$GRAALVM_HOME/bin/native-image" "${args[@]}"
+"$GRAALVM_HOME/bin/native-image" "${args[@]}" "$@"
diff --git a/script/compile.bat b/script/compile.bat
index 56d3396c..51abbc72 100644
--- a/script/compile.bat
+++ b/script/compile.bat
@@ -29,7 +29,12 @@ call %GRAALVM_HOME%\bin\native-image.cmd ^
"-H:+ReportExceptionStackTraces" ^
"--verbose" ^
"--no-fallback" ^
- "%BABASHKA_XMX%"
+ "--enable-preview" ^
+ "--install-exit-handlers" ^
+ "-march=compatibility" ^
+ "-O1" ^
+ "%BABASHKA_XMX%" ^
+ %*
if %errorlevel% neq 0 exit /b %errorlevel%
diff --git a/script/install-graalvm b/script/install-graalvm
index 19d43c5a..dd27675a 100755
--- a/script/install-graalvm
+++ b/script/install-graalvm
@@ -4,34 +4,33 @@ set -euo pipefail
INSTALL_DIR="${1:-$HOME}"
-GRAALVM_VERSION="${GRAALVM_VERSION:-21.2.0}"
+GRAALVM_VERSION="${GRAALVM_VERSION:-22}"
-case "$BABASHKA_PLATFORM" in
- macos)
- GRAALVM_PLATFORM="darwin"
- ;;
- linux)
- GRAALVM_PLATFORM="linux"
- ;;
-esac
+GRAALVM_PLATFORM=$BABASHKA_PLATFORM
case "${BABASHKA_ARCH:-}" in
- aarch64)
- GRAALVM_ARCH="aarch64"
- ;;
- *)
- GRAALVM_ARCH="amd64"
- ;;
+ aarch64)
+ GRAALVM_ARCH="aarch64"
+ ;;
+ *)
+ GRAALVM_ARCH="x64"
+ ;;
esac
-GRAALVM_FILENAME="graalvm-ce-java11-$GRAALVM_PLATFORM-$GRAALVM_ARCH-$GRAALVM_VERSION.tar.gz"
+GRAALVM_DIR_NAME="graalvm-$GRAALVM_VERSION"
+GRAALVM_FILENAME="graalvm-jdk-${GRAALVM_VERSION}_${GRAALVM_PLATFORM}-${GRAALVM_ARCH}_bin.tar.gz"
+DOWNLOAD_URL="https://download.oracle.com/graalvm/22/archive/${GRAALVM_FILENAME}"
pushd "$INSTALL_DIR" >/dev/null
-if ! [ -d "graalvm-ce-java11-$GRAALVM_VERSION" ]; then
- echo "Downloading GraalVM $GRAALVM_PLATFORM-$GRAALVM_ARCH-$GRAALVM_VERSION on '$PWD'..."
- curl -O -sL "https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-$GRAALVM_VERSION/$GRAALVM_FILENAME"
- tar xzf "$GRAALVM_FILENAME"
+if ! [ -d "$GRAALVM_DIR_NAME" ]; then
+ echo "Downloading GraalVM $GRAALVM_PLATFORM-$GRAALVM_ARCH-$GRAALVM_VERSION on '$PWD'..."
+ echo "$DOWNLOAD_URL"
+ curl --fail -LO "$DOWNLOAD_URL"
+ ls -la
+ mkdir "$GRAALVM_DIR_NAME"
+ tar xzvf "$GRAALVM_FILENAME" -C "$GRAALVM_DIR_NAME" --strip-components 1
+ ls -la "$GRAALVM_DIR_NAME"
fi
popd >/dev/null
diff --git a/script/test b/script/test
index 2d6317b9..ad459154 100755
--- a/script/test
+++ b/script/test
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
+set -eo pipefail
+
if [ "$GRAALVM_HOME" != "" ]
then
export JAVA_HOME=$GRAALVM_HOME
@@ -8,7 +10,6 @@ fi
java -version
-set -eo pipefail
unset BABASHKA_PRELOADS
unset BABASHKA_CLASSPATH
unset BABASHKA_PRELOADS_TEST
@@ -16,6 +17,9 @@ unset BABASHKA_PRELOADS_TEST
echo "running tests part 1"
lein "do" clean, test "$@"
+echo "running flaky tests"
+lein "do" clean, test :flaky || true
+
export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
export BABASHKA_PRELOADS_TEST=true
echo "running tests part 2"
@@ -37,3 +41,13 @@ lein test :only babashka.pod-test
export BABASHKA_SOCKET_REPL_TEST=true
lein test :only babashka.impl.socket-repl-test
+
+# test invoking script in subdir with bb.edn in parent dir
+unset BABASHKA_PRELOADS
+unset BABASHKA_CLASSPATH
+pushd test-resources/bb_in_root_script_in_other_dir
+if [[ $BABASHKA_TEST_ENV = "native" ]]
+then
+ ../../bb dir/script.clj
+fi
+popd
diff --git a/script/test.bat b/script/test.bat
index d0fe976e..106caed2 100755
--- a/script/test.bat
+++ b/script/test.bat
@@ -16,7 +16,11 @@ set BABASHKA_POD_TEST=
set BABASHKA_SOCKET_REPL_TEST=
echo "running tests part 1"
-call lein do clean, test :windows || exit /B 1
+call lein do clean, test %* || exit /B 1
+
+echo "running flaky tests"
+REM there's no "or exit" here because we don't want flaky tests to fail the script
+call lein do clean, test :flaky
set BABASHKA_PRELOADS=(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")
set BABASHKA_PRELOADS_TEST=true
diff --git a/script/uberjar b/script/uberjar
index 42025c74..525a2d71 100755
--- a/script/uberjar
+++ b/script/uberjar
@@ -175,8 +175,15 @@ else
BABASHKA_LEIN_PROFILES+=",-feature/rrb-vector"
fi
+mkdir -p resources/META-INF/babashka
cp deps.edn resources/META-INF/babashka/deps.edn
+rm -rf resources/*.class
+# SVM_JAR=$(find -L "$GRAALVM_HOME" | grep svm.jar)
+# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/UrlClassLoaderSubstitutions.java
+# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffSunAwtWwwContentAudioAiff.java
+# "$GRAALVM_HOME/bin/javac" -cp "$SVM_JAR" resources/CutOffMisc.java
+
if [ -z "$BABASHKA_JAR" ]; then
lein with-profiles "$BABASHKA_LEIN_PROFILES,+reflection,-uberjar" do run
lein with-profiles "$BABASHKA_LEIN_PROFILES" do clean, uberjar, metabom
diff --git a/src/aaaa_this_has_to_be_first/because_patches.clj b/src/aaaa_this_has_to_be_first/because_patches.clj
index d0b5cda1..b8651a25 100644
--- a/src/aaaa_this_has_to_be_first/because_patches.clj
+++ b/src/aaaa_this_has_to_be_first/because_patches.clj
@@ -3,28 +3,46 @@
(:require [babashka.impl.patches.datafy]
[babashka.impl.pprint]))
-;; Enable this for scanning requiring-resolve usage:
-;; ---
-;; (def old-requiring-resolve requiring-resolve)
-
-;; (defmacro static-requiring-resolve [sym]
-;; (prn :sym sym)
-;; `(old-requiring-resolve ~sym))
-
-;; (alter-var-root #'requiring-resolve (constantly @#'static-requiring-resolve))
-;; (doto #'requiring-resolve (.setMacro))
-;; ---
-
-;; ((requiring-resolve 'clojure.pprint/pprint) (range 20))
-
-;; Enable this for detecting literal usages of require
-;; ---
-;; (def old-require require)
-
-;; (defmacro static-require [& syms]
-;; (when (meta &form)
-;; (prn :require &form ))
-;; `(old-require ~@syms))
-;; (alter-var-root #'require (constantly @#'static-require))
-;; (doto #'require (.setMacro))
+;; Enable this for scanning requiring usage:
+(def enable-require-scan
+ "(do
+ (def old-require require)
+ (def old-resolve resolve)
+
+ (def our-requiring-resolve (fn [sym]
+ (let [ns (symbol (namespace sym))]
+ (old-require ns)
+ (old-resolve sym))))
+
+ (defn static-requiring-resolve [form _ _]
+ (prn :req-resolve form :args (rest form))
+ `(let [res# (our-requiring-resolve ~@(rest form))]
+ res#))
+
+ (alter-var-root #'requiring-resolve (constantly @#'static-requiring-resolve))
+ (doto #'requiring-resolve (.setMacro))
+
+ (defn static-require [& [&form _bindings & syms]]
+ (when (meta &form)
+ (prn :require &form (meta &form) *file*))
+ `(old-require ~@syms))
+ (alter-var-root #'require (constantly @#'static-require))
+ (doto #'require (.setMacro))
+
+ (alter-var-root #'clojure.core/serialized-require (constantly (fn [& args]
+ (prn :serialized-req args)))))
+
+
+
+ (defn static-resolve [& [&form _bindings & syms]]
+ (when (meta &form)
+ (prn :require &form (meta &form) *file*))
+ `(old-resolve ~@syms))
+ (alter-var-root #'resolve (constantly @#'static-resolve))
+ (doto #'resolve (.setMacro))
+")
+
+
+(when (System/getenv "BABASHKA_REQUIRE_SCAN")
+ (load-string enable-require-scan))
;; ---
diff --git a/src/babashka/deps.clj b/src/babashka/deps.clj
index ea8daa59..817b81d2 100644
--- a/src/babashka/deps.clj
+++ b/src/babashka/deps.clj
@@ -22,7 +22,7 @@
Examples:
- (-> (clojure '[-M -e (+ 1 2 3)] {:out :string}) deref :out) returns
+ (-> (clojure {:out :string} '-M '-e '(+ 1 2 3)]) deref :out) returns
\"6\n\".
(-> @(clojure) :exit) starts a clojure REPL, waits for it
@@ -38,17 +38,13 @@
*out* @sci/out
*err* @sci/err
deps/*dir* (:dir opts)
- deps/*env* (:env opts)
- deps/*extra-env* (:extra-env opts)
- deps/*process-fn* (fn
- ([cmd] (pp/process* {:cmd cmd
- :prev prev
- :opts opts}))
- ([cmd _] (pp/process* {:cmd cmd
- :prev prev
- :opts opts})))
- deps/*exit-fn* (fn
- ([_])
- ([_exit-code msg]
- (throw (Exception. msg))))]
+ deps/*aux-process-fn* (fn [{:keys [cmd out]}]
+ (pp/shell (assoc opts :out out :cmd cmd)))
+ deps/*clojure-process-fn* (fn [{:keys [cmd]}]
+ (pp/process* {:cmd cmd
+ :prev prev
+ :opts opts}))
+ deps/*exit-fn* (fn [{:keys [message]}]
+ (when message
+ (throw (Exception. message))))]
(apply deps/-main cmd))))
diff --git a/src/babashka/dude.clj b/src/babashka/dude.clj
new file mode 100644
index 00000000..6a984cf7
--- /dev/null
+++ b/src/babashka/dude.clj
@@ -0,0 +1,8 @@
+(ns babashka.dude
+ (:require [clojure-csv.core :as csv]
+ [clojure.java.io :as io]
+ [clojure.string :as string]))
+
+csv/x
+io/x
+string/x
diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj
index 561da019..4040ad54 100644
--- a/src/babashka/impl/classes.clj
+++ b/src/babashka/impl/classes.clj
@@ -8,6 +8,18 @@
[sci.core :as sci]
[sci.impl.types :as t]))
+(set! *warn-on-reflection* true)
+
+(def has-of-virtual?
+ (some #(= "ofVirtual" (.getName ^java.lang.reflect.Method %))
+ (.getMethods Thread)))
+
+(def has-domain-sockets?
+ (resolve 'java.net.UnixDomainSocketAddress))
+
+(def has-graal-process-properties?
+ (resolve 'org.graalvm.nativeimage.ProcessProperties))
+
(def base-custom-map
`{clojure.lang.LineNumberingPushbackReader {:allPublicConstructors true
:allPublicMethods true}
@@ -47,7 +59,10 @@
{:name "sleep"}
{:name "start"}
{:name "toString"}
- {:name "yield"}]}
+ {:name "yield"}
+ ~@(when has-of-virtual? [{:name "ofVirtual"}
+ {:name "startVirtualThread"}
+ {:name "isVirtual"}])]}
java.net.URL
{:allPublicConstructors true
:allPublicFields true
@@ -76,7 +91,8 @@
java.util.Arrays
{:methods [{:name "copyOf"}
{:name "copyOfRange"}
- {:name "equals"}]}
+ {:name "equals"}
+ {:name "fill"}]}
;; this fixes clojure.lang.Reflector for Java 11
java.lang.reflect.AccessibleObject
{:methods [{:name "canAccess"}]}
@@ -111,17 +127,21 @@
clojure.lang.RT
{:methods [{:name "aget"}
{:name "aset"}
- {:name "aclone"}]}
+ {:name "aclone"}
+ ;; we expose this via the Compiler/LOADER dynamic var
+ {:name "baseLoader"}]}
clojure.lang.Compiler
{:fields [{:name "specials"}
{:name "CHAR_MAP"}]}
clojure.lang.PersistentHashMap
{:fields [{:name "EMPTY"}]}
clojure.lang.APersistentVector
- {:methods [{:name "indexOf"}]}
+ {:methods [{:name "indexOf"}
+ {:name "contains"}]}
clojure.lang.LazySeq
{:allPublicConstructors true,
- :methods [{:name "indexOf"}]}
+ :methods [{:name "indexOf"}
+ {:name "contains"}]}
clojure.lang.ILookup
{:methods [{:name "valAt"}]}
clojure.lang.IPersistentMap
@@ -140,19 +160,39 @@
{:methods [{:name "hasNext"}
{:name "next"}]}
java.util.TimeZone
- {:methods [{:name "getTimeZone"}]}})
+ {:methods [{:name "getTimeZone"}]}
+ java.net.URLClassLoader
+ {:methods [{:name "close"}
+ {:name "findResource"}
+ {:name "findResources"}
+ {:name "getResourceAsStream"}
+ {:name "getURLs"}]}
+ java.lang.ClassLoader
+ {:methods [{:name "getResource"}
+ {:name "getResources"}
+ {:name "getResourceAsStream"}
+ {:name "getParent"}]}
+ clojure.lang.ARef
+ {:methods [{:name "getWatches"}]}
+ clojure.lang.MapEntry
+ {:allPublicConstructors true
+ :methods [{:name "create"}]}})
(def custom-map
(cond->
- (merge base-custom-map
- proxy/custom-reflect-map)
+ (merge base-custom-map
+ proxy/custom-reflect-map)
features/hsqldb? (assoc `org.hsqldb.dbinfo.DatabaseInformationFull
{:methods [{:name ""
:parameterTypes ["org.hsqldb.Database"]}]}
`java.util.ResourceBundle
{:methods [{:name "getBundle"
:parameterTypes ["java.lang.String","java.util.Locale",
- "java.lang.ClassLoader"]}]})))
+ "java.lang.ClassLoader"]}]})
+
+ has-graal-process-properties?
+ (assoc `org.graalvm.nativeimage.ProcessProperties
+ {:methods [{:name "exec"}]})))
(def java-net-http-classes
"These classes must be initialized at run time since GraalVM 22.1"
@@ -182,7 +222,14 @@
java.net.http.WebSocket$Builder
java.net.http.WebSocket$Listener
java.security.cert.X509Certificate
+ java.security.cert.CertificateFactory
+ javax.crypto.Cipher
javax.crypto.Mac
+ javax.crypto.SecretKey
+ javax.crypto.SecretKeyFactory
+ javax.crypto.spec.GCMParameterSpec
+ javax.crypto.spec.IvParameterSpec
+ javax.crypto.spec.PBEKeySpec
javax.crypto.spec.SecretKeySpec
javax.net.ssl.HostnameVerifier ;; clj-http-lite
javax.net.ssl.HttpsURLConnection ;; clj-http-lite
@@ -194,6 +241,9 @@
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.X509TrustManager
+ javax.net.ssl.X509ExtendedTrustManager
+ javax.net.ssl.SSLSocket
+ javax.net.ssl.SSLSocketFactory
jdk.internal.net.http.HttpClientBuilderImpl
jdk.internal.net.http.HttpClientFacade
jdk.internal.net.http.HttpRequestBuilderImpl
@@ -284,7 +334,9 @@
java.lang.StringBuilder
java.lang.System
java.lang.Throwable
- ;; java.lang.UnsupportedOperationException
+ java.lang.ThreadLocal
+ java.lang.Thread$UncaughtExceptionHandler
+ java.lang.UnsupportedOperationException
java.lang.ref.WeakReference
java.lang.ref.ReferenceQueue
java.lang.ref.Cleaner
@@ -299,11 +351,15 @@
java.net.HttpURLConnection
java.net.InetAddress
java.net.InetSocketAddress
+ java.net.StandardProtocolFamily
java.net.ServerSocket
java.net.Socket
java.net.SocketException
+ ~@(when has-domain-sockets?
+ '[java.net.UnixDomainSocketAddress])
java.net.UnknownHostException
java.net.URI
+ java.net.URISyntaxException
;; java.net.URL, see custom map
java.net.URLConnection
java.net.URLEncoder
@@ -319,6 +375,8 @@
java.nio.file.StandardOpenOption
java.nio.channels.FileChannel
java.nio.channels.FileChannel$MapMode
+ java.nio.channels.ServerSocketChannel
+ java.nio.channels.SocketChannel
java.nio.charset.Charset
java.nio.charset.CoderResult
java.nio.charset.CharsetEncoder
@@ -343,14 +401,17 @@
java.nio.file.attribute.FileTime
java.nio.file.attribute.PosixFilePermission
java.nio.file.attribute.PosixFilePermissions])
+ java.security.spec.PKCS8EncodedKeySpec
java.security.MessageDigest
java.security.DigestInputStream
java.security.Provider
+ java.security.KeyFactory
java.security.KeyStore
java.security.SecureRandom
java.security.Security
java.sql.Date
java.text.ParseException
+ java.text.ParsePosition
;; adds about 200kb, same functionality provided by java.time:
java.text.SimpleDateFormat
~@(when features/java-time?
@@ -378,6 +439,7 @@
java.time.format.DateTimeFormatterBuilder
java.time.format.DateTimeParseException
java.time.format.DecimalStyle
+ java.time.format.FormatStyle
java.time.format.ResolverStyle
java.time.format.SignStyle
java.time.temporal.ChronoField
@@ -386,31 +448,44 @@
java.time.temporal.TemporalAdjusters
java.time.temporal.TemporalAmount
java.time.temporal.TemporalField
+ java.time.temporal.WeekFields
~(symbol "[Ljava.time.temporal.TemporalField;")
java.time.format.TextStyle
java.time.temporal.Temporal
java.time.temporal.TemporalAccessor
- java.time.temporal.TemporalAdjuster])
+ java.time.temporal.TemporalAdjuster
+ java.time.temporal.TemporalQuery
+ ~(symbol "[Ljava.time.temporal.TemporalQuery;")])
java.util.concurrent.atomic.AtomicInteger
java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.AtomicReference
+ java.util.concurrent.Callable
java.util.concurrent.CancellationException
java.util.concurrent.CompletionException
+ java.util.concurrent.CountDownLatch
java.util.concurrent.ExecutionException
java.util.concurrent.Executor
+ java.util.concurrent.ExecutorService
+ java.util.concurrent.BlockingQueue
+ java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.LinkedBlockingQueue
+ java.util.concurrent.ScheduledFuture
java.util.concurrent.ScheduledThreadPoolExecutor
+ java.util.concurrent.Semaphore
+ java.util.concurrent.ThreadFactory
java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.ThreadPoolExecutor$AbortPolicy
java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy
java.util.concurrent.ThreadPoolExecutor$DiscardOldestPolicy
java.util.concurrent.ThreadPoolExecutor$DiscardPolicy
+ java.util.concurrent.ExecutorService
java.util.concurrent.ScheduledExecutorService
java.util.concurrent.Future
java.util.concurrent.FutureTask
java.util.concurrent.CompletableFuture
java.util.concurrent.Executors
java.util.concurrent.TimeUnit
+ java.util.jar.Attributes
java.util.jar.Attributes$Name
java.util.jar.JarFile
java.util.jar.JarEntry
@@ -420,6 +495,7 @@
java.util.jar.Manifest
java.util.stream.BaseStream
java.util.stream.Stream
+ java.util.stream.IntStream
java.util.Random
java.util.regex.Matcher
java.util.regex.Pattern
@@ -432,6 +508,7 @@
java.util.Base64$Encoder
java.util.Date
java.util.HashMap
+ java.util.HashSet
java.util.IdentityHashMap
java.util.InputMismatchException
java.util.List
@@ -452,6 +529,8 @@
java.util.function.BiFunction
java.util.function.Predicate
java.util.function.Supplier
+ java.util.zip.CheckedInputStream
+ java.util.zip.CRC32
java.util.zip.Inflater
java.util.zip.InflaterInputStream
java.util.zip.Deflater
@@ -485,7 +564,6 @@
~@(when features/yaml? '[org.yaml.snakeyaml.error.YAMLException])
~@(when features/hsqldb? '[org.hsqldb.jdbcDriver])]
:constructors [clojure.lang.Delay
- clojure.lang.MapEntry
clojure.lang.LineNumberingPushbackReader
java.io.EOFException]
:methods [borkdude.graal.LockFix] ;; support for locking
@@ -527,19 +605,23 @@
clojure.lang.IRef
clojure.lang.ISeq
clojure.lang.IPersistentVector
+ clojure.lang.ITransientSet
clojure.lang.ITransientVector
clojure.lang.Iterate
clojure.lang.LispReader$Resolver
+ clojure.lang.LongRange
clojure.lang.Named
clojure.lang.Keyword
clojure.lang.PersistentArrayMap
clojure.lang.PersistentHashSet
clojure.lang.PersistentList
+ clojure.lang.PersistentList$EmptyList
clojure.lang.PersistentQueue
clojure.lang.PersistentStructMap
clojure.lang.PersistentTreeMap
clojure.lang.PersistentTreeSet
clojure.lang.PersistentVector
+ clojure.lang.Range
clojure.lang.Ratio
clojure.lang.ReaderConditional
clojure.lang.Repeat
@@ -557,7 +639,6 @@
java.lang.LinkageError
java.lang.ThreadDeath
java.lang.VirtualMachineError
- java.net.URLClassLoader
java.sql.Timestamp
java.util.concurrent.TimeoutException
java.util.Collection
@@ -574,7 +655,27 @@
(:instance-checks classes))
m (apply hash-map
(for [c classes
- c [(list 'quote c) c]]
+ c [(list 'quote c) (cond-> `{:class ~c}
+ (= 'java.lang.Class c)
+ (assoc :static-methods
+ {(list 'quote 'forName)
+ `(fn
+ ([_# ^String class-name#]
+ (Class/forName class-name#))
+ ([_# ^String class-name# initialize# ^java.lang.ClassLoader clazz-loader#]
+ (Class/forName class-name#)))})
+ (= 'java.lang.Thread c)
+ (assoc :static-methods
+ {(list 'quote 'sleep)
+ `(fn
+ ([_# x#]
+ (if (instance? Number x#)
+ (let [x# (long x#)]
+ (Thread/sleep x#))
+ (let [^java.time.Duration x# x#]
+ (Thread/sleep x#))))
+ ([_# ^java.lang.Long millis# ^java.lang.Long nanos#]
+ (Thread/sleep millis# nanos#)))}))]]
c))
m (assoc m :public-class
(fn [v]
@@ -607,6 +708,8 @@
java.nio.file.FileSystem
(instance? java.nio.file.PathMatcher v)
java.nio.file.PathMatcher
+ (instance? java.util.stream.IntStream v)
+ java.util.stream.IntStream
(instance? java.util.stream.BaseStream v)
java.util.stream.BaseStream
(instance? java.nio.ByteBuffer v)
@@ -619,6 +722,10 @@
java.nio.CharBuffer
(instance? java.nio.channels.FileChannel v)
java.nio.channels.FileChannel
+ (instance? java.nio.channels.ServerSocketChannel v)
+ java.nio.channels.ServerSocketChannel
+ (instance? java.nio.channels.SocketChannel v)
+ java.nio.channels.SocketChannel
(instance? java.net.CookieStore v)
java.net.CookieStore
;; this makes interop on reified classes work
@@ -626,18 +733,38 @@
(instance? sci.impl.types.IReified v)
(first (t/getInterfaces v))
;; fix for #1061
- (instance? java.io.Closeable v)
- java.io.Closeable
+ (instance? java.net.URLClassLoader v)
+ java.net.URLClassLoader
+ (instance? java.lang.ClassLoader v)
+ java.lang.ClassLoader
(instance? java.nio.file.attribute.BasicFileAttributes v)
java.nio.file.attribute.BasicFileAttributes
(instance? java.util.concurrent.Future v)
java.util.concurrent.Future
(instance? java.util.concurrent.ScheduledExecutorService v)
java.util.concurrent.ScheduledExecutorService
+ (instance? java.util.concurrent.ExecutorService v)
+ java.util.concurrent.ExecutorService
(instance? java.util.Iterator v)
java.util.Iterator
+ (instance? javax.crypto.SecretKey v)
+ javax.crypto.SecretKey
+ (instance? javax.net.ssl.SSLSocketFactory v)
+ javax.net.ssl.SSLSocketFactory
+ (instance? javax.net.ssl.SSLSocket v)
+ javax.net.ssl.SSLSocket
+ (instance? java.lang.Thread v)
+ java.lang.Thread
+ (instance? java.security.cert.X509Certificate v)
+ java.security.cert.X509Certificate
+ (instance? java.io.Console v)
+ java.io.Console
+ (instance? java.util.Set v)
+ java.util.Set
+ (instance? java.io.Closeable v)
+ java.io.Closeable
;; keep commas for merge friendliness
- ,,,)))
+ )))
m (assoc m (list 'quote 'clojure.lang.Var) 'sci.lang.Var)
m (assoc m (list 'quote 'clojure.lang.Namespace) 'sci.lang.Namespace)]
m))
@@ -648,6 +775,14 @@
allowed to be initialized at build time."
(gen-class-map))
+#_(let [class-name (str c)]
+ (cond-> (Class/forName class-name)
+ (= "java.lang.Class" class-name)
+ (->> (hash-map :static-methods {'forName (fn [class-name]
+ (prn :class-for)
+ (Class/forName class-name))}
+ :class))))
+
(def class-map
"A delay to delay initialization of java-net-http classes to run time, since GraalVM 22.1"
(delay (persistent! (reduce (fn [acc c]
@@ -664,6 +799,7 @@
BigInteger java.math.BigInteger
Boolean java.lang.Boolean
Byte java.lang.Byte
+ Callable java.util.concurrent.Callable
Character java.lang.Character
CharSequence java.lang.CharSequence
Class java.lang.Class
@@ -689,9 +825,10 @@
Number java.lang.Number
NumberFormatException java.lang.NumberFormatException
Object java.lang.Object
+ Runnable java.lang.Runnable
Runtime java.lang.Runtime
RuntimeException java.lang.RuntimeException
- Process java.lang.Process
+ Process java.lang.Process
ProcessBuilder java.lang.ProcessBuilder
Short java.lang.Short
StackTraceElement java.lang.StackTraceElement
@@ -699,11 +836,13 @@
StringBuilder java.lang.StringBuilder
System java.lang.System
Thread java.lang.Thread
+ ThreadLocal java.lang.ThreadLocal
+ Thread$UncaughtExceptionHandler java.lang.Thread$UncaughtExceptionHandler
Throwable java.lang.Throwable
VirtualMachineError java.lang.VirtualMachineError
ThreadDeath java.lang.ThreadDeath
Void java.lang.Void
- ;; UnsupportedOperationException java.lang.UnsupportedOperationException
+ UnsupportedOperationException java.lang.UnsupportedOperationException
})
(defn reflection-file-entries []
@@ -746,13 +885,13 @@
"resources/META-INF/native-image/babashka/babashka/reflect-config.json")
(json/generate-string all-entries {:pretty true}))))
-(defn public-declared-method? [c m]
+(defn public-declared-method? [^Class c ^java.lang.reflect.Method m]
(and (= c (.getDeclaringClass m))
(not (.getAnnotation m Deprecated))))
-(defn public-declared-method-names [c]
+(defn public-declared-method-names [^Class c]
(->> (.getMethods c)
- (keep (fn [m]
+ (keep (fn [^java.lang.reflect.Method m]
(when (public-declared-method? c m)
{:class c
:name (.getName m)})))
@@ -760,8 +899,9 @@
(sort-by :name)
(vec)))
-(defn all-classes []
+(defn all-classes
"Returns every java.lang.Class instance Babashka supports."
+ []
(->> (reflection-file-entries)
(map :name)
(map #(Class/forName %))))
@@ -779,6 +919,4 @@
(public-declared-method-names java.net.URL)
(public-declared-method-names java.util.Properties)
- (all-classes)
-
- )
+ (all-classes))
diff --git a/src/babashka/impl/classpath.clj b/src/babashka/impl/classpath.clj
index 11691390..6da8b59f 100644
--- a/src/babashka/impl/classpath.clj
+++ b/src/babashka/impl/classpath.clj
@@ -5,66 +5,51 @@
[clojure.java.io :as io]
[clojure.string :as str]
[sci.core :as sci])
- (:import [java.util.jar JarFile Manifest]
+ (:import [java.util.jar Manifest]
(java.net URL)))
(set! *warn-on-reflection* true)
-(defprotocol IResourceResolver
- (getResource [this paths opts])
- (getResources [this paths opts]))
-
-(deftype DirectoryResolver [path]
- IResourceResolver
- (getResource [_ resource-paths url?]
- (some
- (fn [resource-path]
- (let [f (io/file path resource-path)]
- (when (.exists f)
- (if url?
- ;; manual conversion, faster than going through .toURI
- (java.net.URL. "file" nil (.getAbsolutePath f))
- {:file (.getAbsolutePath f)
- :source (slurp f)}))))
- resource-paths)))
-
-(defn path-from-jar
- [^java.io.File jar-file resource-paths url?]
- (with-open [jar (JarFile. jar-file)]
- (some (fn [path]
- (when-let [entry (.getEntry jar path)]
- (if url?
- ;; manual conversion, faster than going through .toURI
- (java.net.URL. "jar" nil
- (str "file:" (.getAbsolutePath jar-file) "!/" path))
- {:file path
- :source (slurp (.getInputStream jar entry))})))
- resource-paths)))
-
-(deftype JarFileResolver [jar-file]
- IResourceResolver
- (getResource [_ resource-paths url?]
- (path-from-jar jar-file resource-paths url?)))
-
-(defn part->entry [part]
- (when-not (str/blank? part)
- (if (str/ends-with? part ".jar")
- (JarFileResolver. (io/file part))
- (DirectoryResolver. (io/file part)))))
-
-(deftype Loader [entries]
- IResourceResolver
- (getResource [_ resource-paths opts]
- (some #(getResource % resource-paths opts) entries))
- (getResources [_ resource-paths opts]
- (keep #(getResource % resource-paths opts) entries)))
+(defn getResource [^babashka.impl.URLClassLoader class-loader resource-paths url?]
+ (some (fn [resource]
+ (when-let [^java.net.URL res (.findResource class-loader resource)]
+ (if url?
+ res
+ {:file (if (= "jar" (.getProtocol res))
+ resource
+ (.getFile res))
+ :source (slurp res)})))
+ resource-paths))
(def path-sep (System/getProperty "path.separator"))
-(defn loader [^String classpath]
- (let [parts (.split classpath path-sep)
- entries (keep part->entry parts)]
- (Loader. entries)))
+(defn ->url ^java.net.URL [^String s]
+ (.toURL (java.io.File. s)))
+
+(defn new-loader ^babashka.impl.URLClassLoader
+ ([paths]
+ (babashka.impl.URLClassLoader. (into-array java.net.URL (map ->url paths)))))
+
+(def ^babashka.impl.URLClassLoader the-url-loader (delay (new-loader [])))
+
+(defn add-classpath
+ "Adds extra-classpath, a string as for example returned by clojure
+ -Spath, to the current classpath."
+ [^String extra-classpath]
+ (let [paths (.split extra-classpath path-sep)
+ paths (map ->url paths)
+ loader @the-url-loader]
+ (run! (fn [path]
+ (._addURL ^babashka.impl.URLClassLoader loader path)
+ loader)
+ paths)
+ ;; (run! prn (.getURLs the-url-loader))
+ (System/setProperty "java.class.path"
+ (let [system-cp (System/getProperty "java.class.path")]
+ (-> (cond-> system-cp
+ (not (str/blank? system-cp)) (str path-sep))
+ (str extra-classpath)))))
+ nil)
(defn resource-paths [namespace]
(let [ns-str (name namespace)
@@ -86,33 +71,20 @@
(.getValue "Main-Class")
(demunge))))
-(def cp-state (atom nil))
-
-(defn add-classpath
- "Adds extra-classpath, a string as for example returned by clojure
- -Spath, to the current classpath."
- [extra-classpath]
- (swap! cp-state
- (fn [{:keys [:cp]}]
- (let [new-cp
- (if-not cp extra-classpath
- (str cp path-sep extra-classpath))]
- {:loader (loader new-cp)
- :cp new-cp})))
- nil)
-
(defn split-classpath
"Returns the classpath as a seq of strings, split by the platform
specific path separator."
- ([^String cp] (vec (.split cp path-sep))))
+ ([^String cp] (vec (when cp (.split cp path-sep)))))
(defn get-classpath
"Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath."
[]
- (:cp @cp-state))
+ (let [cp (System/getProperty "java.class.path")]
+ (when-not (str/blank? cp)
+ cp)))
(defn resource
- (^URL [path] (when-let [st @cp-state] (resource (:loader st) path)))
+ (^URL [path] (resource @the-url-loader path))
(^URL [loader path]
(if (str/starts-with? path "/") nil ;; non-relative paths always return nil
(getResource loader [path] true))))
@@ -132,4 +104,3 @@
(def l (loader cp))
(source-for-namespace l 'babashka.impl.cheshire nil)
(time (:file (source-for-namespace l 'cheshire.core nil)))) ;; 20ms -> 2.25ms
-
diff --git a/src/babashka/impl/cli.clj b/src/babashka/impl/cli.clj
index 753e99a7..1ec08daf 100644
--- a/src/babashka/impl/cli.clj
+++ b/src/babashka/impl/cli.clj
@@ -17,18 +17,22 @@
(let [extra-opts '%s
sym `%s
the-var (requiring-resolve sym)
+ _ (when-not the-var
+ (throw (ex-info (str \"Could not resolve sym to a function: \" sym) {:babashka/exit 1})))
the-var-meta (meta the-var)
ns (:ns (meta the-var))
ns-meta (meta ns)
ct (babashka.tasks/current-task)
+ exec-args (babashka.cli/merge-opts (:exec-args (:org.babashka/cli ns-meta))
+ (:exec-args (:org.babashka/cli the-var-meta))
+ (:exec-args (:org.babashka/cli ct))
+ (:exec-args ct)
+ (:exec-args extra-opts))
cli-opts (babashka.cli/merge-opts (:org.babashka/cli ns-meta)
(:org.babashka/cli the-var-meta)
(:org.babashka/cli ct)
extra-opts)
- task-exec-args (:exec-args ct)
- cli-exec-args (:exec-args cli-opts)
- exec-args {:exec-args (babashka.cli/merge-opts cli-exec-args task-exec-args)}
- cli-opts (babashka.cli/merge-opts exec-args cli-opts)
+ cli-opts (assoc cli-opts :exec-args exec-args)
opts (babashka.cli/parse-opts *command-line-args* cli-opts)]
(the-var opts))"
(random-uuid)
diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj
index 56da8704..64438f47 100644
--- a/src/babashka/impl/clojure/core.clj
+++ b/src/babashka/impl/clojure/core.clj
@@ -15,15 +15,6 @@
(defn locking* [form bindings v f & args]
(apply @#'locking/locking form bindings v f args))
-(defn time*
- "Evaluates expr and prints the time it took. Returns the value of
- expr."
- [_ _ expr]
- `(let [start# (. System (nanoTime))
- ret# ~expr]
- (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
- ret#))
-
(defn core-dynamic-var
([sym] (core-dynamic-var sym nil))
([sym init-val] (sci/new-dynamic-var sym init-val {:ns clojure-core-ns})))
@@ -34,6 +25,8 @@
(def compile-files (core-dynamic-var '*compile-files* false))
(def unchecked-math (core-dynamic-var '*unchecked-math* false))
(def math-context (core-dynamic-var '*math-context*))
+(def compile-path (core-dynamic-var '*compile-path* *compile-path*))
+(def compiler-options (core-dynamic-var '*compiler-options*))
(defn read+string
"Added for compatibility. Must be used with
@@ -158,7 +151,6 @@
'shutdown-agents (copy-core-var shutdown-agents)
'slurp (copy-core-var slurp)
'spit (copy-core-var spit)
- 'time (macrofy 'time time*)
'Throwable->map (copy-core-var Throwable->map)
'tap> (copy-core-var tap>)
'add-tap (copy-core-var add-tap)
@@ -173,6 +165,8 @@
'*compile-files* compile-files
'*unchecked-math* unchecked-math
'*math-context* math-context
+ '*compiler-options* compiler-options
+ '*compile-path* compile-path
'with-precision (sci/copy-var with-precision clojure-core-ns)
'-with-precision (sci/copy-var -with-precision clojure-core-ns)
;; STM
@@ -199,5 +193,7 @@
'print-method (sci/copy-var print-method clojure-core-ns)
'print-dup (sci/copy-var print-dup clojure-core-ns)
'PrintWriter-on (sci/copy-var PrintWriter-on clojure-core-ns)
- '*compiler-options* (sci/new-dynamic-var '*compiler-options*)}
+ 'set-agent-send-executor! (sci/copy-var set-agent-send-executor! clojure-core-ns)
+ 'set-agent-send-off-executor! (sci/copy-var set-agent-send-off-executor! clojure-core-ns)
+ }
)
diff --git a/src/babashka/impl/clojure/core/async.clj b/src/babashka/impl/clojure/core/async.clj
index 391c4d9b..4d0d22a3 100644
--- a/src/babashka/impl/clojure/core/async.clj
+++ b/src/babashka/impl/clojure/core/async.clj
@@ -6,8 +6,14 @@
[sci.impl.copy-vars :refer [macrofy]]
[sci.impl.vars :as vars]))
+(set! *warn-on-reflection* true)
+
(def ^java.util.concurrent.Executor executor @#'async/thread-macro-executor)
+(def ^java.util.concurrent.Executor virtual-executor
+ (try (eval '(java.util.concurrent.Executors/newVirtualThreadPerTaskExecutor))
+ (catch Exception _ nil)))
+
(defn thread-call
"Executes f in another thread, returning immediately to the calling
thread. Returns a channel which will receive the result of calling
@@ -26,10 +32,32 @@
(async/close! c))))))
c))
+(defn -vthread-call
+ "Executes f in another virtual thread, returning immediately to the calling
+ thread. Returns a channel which will receive the result of calling
+ f when completed, then close."
+ [f]
+ (let [c (async/chan 1)]
+ (let [binds (vars/get-thread-binding-frame)]
+ (.execute virtual-executor
+ (fn []
+ (vars/reset-thread-binding-frame binds)
+ (try
+ (let [ret (f)]
+ (when-not (nil? ret)
+ (async/>!! c ret)))
+ (finally
+ (async/close! c))))))
+ c))
+
(defn thread
[_ _ & body]
`(~'clojure.core.async/thread-call (fn [] ~@body)))
+(defn -vthread
+ [_ _ & body]
+ `(~'clojure.core.async/-vthread-call (fn [] ~@body)))
+
(defn alt!!
"Like alt!, except as if by alts!!, will block until completed, and
not intended for use in (go ...) blocks."
@@ -38,10 +66,19 @@
(defn go-loop
[_ _ bindings & body]
- (list 'clojure.core.async/thread (list* 'loop bindings body)))
+ (list 'clojure.core.async/go (list* 'loop bindings body)))
(def core-async-namespace (sci/create-ns 'clojure.core.async nil))
+(defn timeout [ms]
+ (if virtual-executor
+ (let [chan (async/chan nil)]
+ (.execute virtual-executor (fn []
+ (Thread/sleep (long ms))
+ (async/close! chan)))
+ chan)
+ (async/timeout ms)))
+
(def async-namespace
{:obj core-async-namespace
'! (copy-var async/>!! core-async-namespace {:name '>!})
'alt! (macrofy 'alt! alt!! core-async-namespace)
@@ -119,3 +159,4 @@
(def async-protocols-namespace
{:obj async-protocols-ns
'ReadPort (copy-var protocols/ReadPort async-protocols-ns)})
+;; trigger CI
diff --git a/src/babashka/impl/clojure/java/browse.clj b/src/babashka/impl/clojure/java/browse.clj
index 37db104b..25718853 100644
--- a/src/babashka/impl/clojure/java/browse.clj
+++ b/src/babashka/impl/clojure/java/browse.clj
@@ -25,7 +25,7 @@
(case os
:mac (sh "open" url)
:linux (sh "xdg-open" url)
- :windows (sh "cmd" "/C" "start" url)))))
+ :windows (sh "cmd" "/C" "start" (.replace url "&" "^&"))))))
(def browse-namespace
{'*open-url-script* open-url-script
diff --git a/src/babashka/impl/clojure/reflect.clj b/src/babashka/impl/clojure/reflect.clj
new file mode 100644
index 00000000..26e97244
--- /dev/null
+++ b/src/babashka/impl/clojure/reflect.clj
@@ -0,0 +1,7 @@
+(ns babashka.impl.clojure.reflect
+ (:require [clojure.reflect]
+ [sci.core :as sci]))
+
+(def rns (sci/create-ns 'clojure.reflect))
+
+(def reflect-namespace {'reflect (sci/copy-var clojure.reflect/reflect rns)})
diff --git a/src/babashka/impl/clojure/test.clj b/src/babashka/impl/clojure/test.clj
index 8903e911..05d01dba 100644
--- a/src/babashka/impl/clojure/test.clj
+++ b/src/babashka/impl/clojure/test.clj
@@ -316,8 +316,8 @@
Does nothing if *report-counters* is nil."
{:added "1.1"}
[name]
- (when @report-counters
- (swap! @report-counters update-in [name] (fnil inc 0))))
+ (when-let [rc @report-counters]
+ (dosync (commute rc update-in [name] (fnil inc 0)))))
;;; TEST RESULT REPORTING
@@ -660,14 +660,12 @@
;;; DEFINING FIXTURES
-(def ^:private ns->fixtures (atom {}))
-
(defn- add-ns-meta
"Adds elements in coll to the current namespace metadata as the
value of key."
{:added "1.1"}
[key coll]
- (swap! ns->fixtures assoc-in [(sci-namespaces/sci-ns-name @sci/ns) key] coll))
+ (alter-meta! @sci/ns assoc key coll))
(defmulti use-fixtures
"Wrap test runs in a fixture function to perform setup and
@@ -677,10 +675,10 @@
(fn [fixture-type & args] fixture-type))
(defmethod use-fixtures :each [fixture-type & args]
- (add-ns-meta ::each-fixtures args))
+ (add-ns-meta :clojure.test/each-fixtures args))
(defmethod use-fixtures :once [fixture-type & args]
- (add-ns-meta ::once-fixtures args))
+ (add-ns-meta :clojure.test/once-fixtures args))
(defn- default-fixture
"The default, empty, fixture function. Just calls its argument."
@@ -731,10 +729,8 @@
[vars]
(doseq [[ns vars] (group-by (comp :ns meta) vars)
:when ns]
- (let [ns-name (sci-namespaces/sci-ns-name ns)
- fixtures (get @ns->fixtures ns-name)
- once-fixture-fn (join-fixtures (::once-fixtures fixtures))
- each-fixture-fn (join-fixtures (::each-fixtures fixtures))]
+ (let [once-fixture-fn (join-fixtures (:clojure.test/once-fixtures (meta ns)))
+ each-fixture-fn (join-fixtures (:clojure.test/each-fixtures (meta ns)))]
(once-fixture-fn
(fn []
(doseq [v vars]
@@ -758,7 +754,7 @@
*report-counters*."
{:added "1.1"}
[ctx ns]
- (sci/binding [report-counters (atom @initial-report-counters)]
+ (sci/binding [report-counters (ref @initial-report-counters)]
(let [ns-obj (sci-namespaces/sci-the-ns ctx ns)]
(do-report {:type :begin-test-ns, :ns ns-obj})
;; If the namespace has a test-ns-hook function, call that:
@@ -809,7 +805,7 @@
"Runs the tests for a single Var, with fixtures executed around the test, and summary output after."
{:added "1.11"}
[v]
- (sci/binding [report-counters (atom @initial-report-counters)]
+ (sci/binding [report-counters (ref @initial-report-counters)]
(let [ns-obj (-> v meta :ns)
summary (do
(do-report {:type :begin-test-ns
diff --git a/src/babashka/impl/clojure/tools/reader.clj b/src/babashka/impl/clojure/tools/reader.clj
index 29f67289..7e942e67 100644
--- a/src/babashka/impl/clojure/tools/reader.clj
+++ b/src/babashka/impl/clojure/tools/reader.clj
@@ -1,9 +1,11 @@
(ns babashka.impl.clojure.tools.reader
- (:refer-clojure :exclude [read])
+ (:refer-clojure :exclude [read read-string])
(:require
+ [clojure.tools.reader.reader-types :as rt]
[edamame.core :as e]
[sci.core :as sci]
- [clojure.tools.reader.reader-types :as rt]))
+ [sci.ctx-store :as ctx]
+ [sci.impl.parser :as p]))
(def rns (sci/create-ns 'clojure.tools.reader))
@@ -15,6 +17,15 @@
:location? seq?
:end-location false}))
+(def default-data-reader-fn (sci/new-dynamic-var '*default-data-reader-fn* nil {:ns rns}))
+(def alias-map (sci/new-dynamic-var '*alias-map* nil {:ns rns}))
+
+(defn resolve-tag [sym]
+ ;; https://github.com/clojure/tools.reader/blob/ff18b1b872398a99e3e2941a0ed9abc0c2dec151/src/main/clojure/clojure/tools/reader.clj#L858
+ (or (default-data-readers sym)
+ (when-let [f @default-data-reader-fn]
+ (f sym))))
+
;; Added for compatibility with tools.namespace
(defn read
"Reads the first object from an IPushbackReader or a java.io.PushbackReader.
@@ -38,7 +49,17 @@
([{eof :eof :as opts :or {eof :eofthrow}} reader]
(let [opts (assoc default-opts
:read-cond (:read-cond opts)
- :features (:features opts))
+ :features (:features opts)
+ :readers (fn [sym]
+ (resolve-tag sym))
+ :auto-resolve (fn [alias]
+ (if (= :current alias)
+ (symbol (str @sci/ns))
+ (or (when-let [alias-map @alias-map]
+ (@alias-map alias))
+ (sci/eval-form (ctx/get-ctx)
+ (list 'get '(ns-aliases *ns*)
+ (list 'quote alias)))))))
v (e/parse-next reader opts)]
(if (identical? ::e/eof v)
(if (identical? :eofthrow eof)
@@ -53,4 +74,18 @@
sentinel)
v))))
-(def reader-namespace {'read (sci/copy-var read rns)})
+(defn read-string
+ ([s] (read-string nil s))
+ ([opts s]
+ (when (and s (not (identical? s "")))
+ (read opts (rt/string-push-back-reader s)))))
+
+(defn resolve-symbol [sym]
+ (p/fully-qualify (ctx/get-ctx) sym))
+
+(def reader-namespace
+ {'read (sci/copy-var read rns)
+ 'read-string (sci/copy-var read-string rns)
+ 'resolve-symbol (sci/copy-var resolve-symbol rns)
+ '*default-data-reader-fn* default-data-reader-fn
+ '*alias-map* alias-map})
diff --git a/src/babashka/impl/clojure/tools/reader_types.clj b/src/babashka/impl/clojure/tools/reader_types.clj
index 15045405..92a6a1ca 100644
--- a/src/babashka/impl/clojure/tools/reader_types.clj
+++ b/src/babashka/impl/clojure/tools/reader_types.clj
@@ -15,4 +15,5 @@
'read-char (sci/copy-var rt/read-char rtns)
'unread (sci/copy-var rt/unread rtns)
'source-logging-push-back-reader (sci/copy-var rt/source-logging-push-back-reader rtns)
- 'source-logging-reader? (sci/copy-var rt/source-logging-reader? rtns)})
+ 'source-logging-reader? (sci/copy-var rt/source-logging-reader? rtns)
+ 'string-push-back-reader (sci/copy-var rt/string-push-back-reader rtns)})
diff --git a/src/babashka/impl/deps.clj b/src/babashka/impl/deps.clj
index c6cfb413..7d737376 100644
--- a/src/babashka/impl/deps.clj
+++ b/src/babashka/impl/deps.clj
@@ -3,6 +3,7 @@
[babashka.fs :as fs]
[babashka.impl.classpath :as cp]
[babashka.impl.common :refer [bb-edn]]
+ [babashka.process :as process]
[borkdude.deps :as deps]
[clojure.string :as str]
[sci.core :as sci]))
@@ -59,42 +60,61 @@
then used to resolve dependencies in babashka."
([deps-map] (add-deps deps-map nil))
([deps-map {:keys [:aliases :env :extra-env :force]}]
- (when-let [paths (:paths deps-map)]
- (let [paths (if-let [deps-root (:deps-root @bb-edn)]
- (let [deps-root (fs/absolutize deps-root)
- paths (mapv #(str (fs/file deps-root %)) paths)]
- paths)
- paths)]
- (cp/add-classpath (str/join cp/path-sep paths))))
- (let [need-deps? (or (seq (:deps deps-map))
- (and (:aliases deps-map)
- aliases))]
- (when need-deps?
- (let [deps-map (dissoc deps-map
- ;; paths are added manually above
- ;; extra-paths are added as :paths in tasks
- :paths :tasks :raw :file :deps-root
- :min-bb-version)]
- (binding [*print-namespace-maps* false]
- (let [deps-map (assoc-in deps-map [:aliases :org.babashka/defaults]
- {:replace-paths [] ;; babashka sets paths manually
- :classpath-overrides (cond->
- '{org.clojure/clojure ""
- org.clojure/spec.alpha ""}
- ;; only remove core specs when they are not mentioned in deps map
- (not (str/includes? (str deps-map) "org.clojure/core.specs.alpha"))
- (assoc 'org.clojure/core.specs.alpha ""))})
- args (list "-Srepro" ;; do not include deps.edn from user config
- "-Spath" "-Sdeps" (str deps-map)
- "-Sdeps-file" "") ;; we reset deps file so the local deps.edn isn't used
- args (if force (cons "-Sforce" args) args)
- args (concat args [(str "-A:" (str/join ":" (cons ":org.babashka/defaults" aliases)))])
- cp (with-out-str (binding [deps/*env* env
- deps/*extra-env* extra-env]
- (apply deps/-main args)))
- cp (str/trim cp)
- cp (str/replace cp (re-pattern (str cp/path-sep "+$")) "")]
- (cp/add-classpath cp))))))))
+ (let [deps-root (:deps-root @bb-edn)]
+ (when-let [paths (:paths deps-map)]
+ (let [paths (if deps-root
+ (let [deps-root (fs/absolutize deps-root)
+ paths (mapv #(str (fs/file deps-root %)) paths)]
+ paths)
+ paths)]
+ (cp/add-classpath (str/join cp/path-sep paths))))
+ (let [need-deps? (or (seq (:deps deps-map))
+ (and (:aliases deps-map)
+ aliases))]
+ (when need-deps?
+ (let [deps-map (dissoc deps-map
+ ;; paths are added manually above
+ ;; extra-paths are added as :paths in tasks
+ :paths :tasks :raw :file :deps-root
+ :min-bb-version)
+ ;; associate deps-root to avoid cache conflict between different
+ ;; bb.edns with relative local/roots by the same name NOTE:
+ ;; deps-root is nil when bb.edn isn't used, so clashes may still
+ ;; happen with dynamic add-deps, but at least we don't invoke
+ ;; clojure CLI's java process each time we call a script from a
+ ;; different directory.
+ deps-map (assoc deps-map :deps-root (str deps-root))]
+ (binding [*print-namespace-maps* false]
+ (let [deps-map (assoc-in deps-map [:aliases :org.babashka/defaults]
+ {:replace-paths [] ;; babashka sets paths manually
+ :classpath-overrides (cond->
+ '{org.clojure/clojure ""
+ org.clojure/spec.alpha ""}
+ ;; only remove core specs when they are not mentioned in deps map
+ (not (str/includes? (str deps-map) "org.clojure/core.specs.alpha"))
+ (assoc 'org.clojure/core.specs.alpha ""))})
+ args (list "-Srepro" ;; do not include deps.edn from user config
+ "-Spath" "-Sdeps" (str deps-map)
+ "-Sdeps-file" "__babashka_no_deps_file__.edn") ;; we reset deps file so the local deps.edn isn't used
+ args (if force (cons "-Sforce" args) args)
+ args (concat args [(str "-A:" (str/join ":" (cons ":org.babashka/defaults" aliases)))])
+ bindings (cond->
+ {#'deps/*aux-process-fn* (fn [{:keys [cmd out]}]
+ (process/shell
+ {:cmd cmd
+ :out out
+ :env env
+ :dir (when deps-root (str deps-root))
+ :extra-env extra-env}))
+ #'deps/*exit-fn* (fn [{:keys [message]}]
+ (when message
+ (throw (Exception. message))))}
+ deps-root (assoc #'deps/*dir* (str deps-root)))
+ cp (with-out-str (with-bindings bindings
+ (apply deps/-main args)))
+ cp (str/trim cp)
+ cp (str/replace cp (re-pattern (str cp/path-sep "+$")) "")]
+ (cp/add-classpath cp)))))))))
(def deps-namespace
{'add-deps (sci/copy-var add-deps dns)
diff --git a/src/babashka/impl/http_client.clj b/src/babashka/impl/http_client.clj
new file mode 100644
index 00000000..c07ccfe7
--- /dev/null
+++ b/src/babashka/impl/http_client.clj
@@ -0,0 +1,15 @@
+(ns babashka.impl.http-client
+ (:require
+ [babashka.http-client]
+ [babashka.http-client.websocket]
+ [sci.core :as sci]))
+
+(def hns (sci/create-ns 'babashka.http-client))
+(def wns (sci/create-ns 'babashka.http-client.websocket))
+
+(def http-client-namespace
+ (sci/copy-ns babashka.http-client hns))
+
+(def http-client-websocket-namespace
+ (sci/copy-ns babashka.http-client.websocket wns))
+
diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj
index 5b3569cb..ab3c0c28 100644
--- a/src/babashka/impl/nrepl_server.clj
+++ b/src/babashka/impl/nrepl_server.clj
@@ -1,11 +1,18 @@
(ns babashka.impl.nrepl-server
{:no-doc true}
(:require
- [babashka.impl.clojure.core]
+ [babashka.impl.classpath :as cp]
+ [babashka.impl.clojure.core :as core-extras]
[babashka.impl.common :as common]
+ [babashka.nrepl.impl.server :refer [process-msg]]
[babashka.nrepl.server :as server]
[sci.core :as sci]))
+(defmethod process-msg :classpath [rf result m]
+ (rf result {:response {"status" ["done"]
+ "classpath" (cp/split-classpath (cp/get-classpath))}
+ :response-for (:msg m)}))
+
(defn start-server!
([]
(start-server! nil))
@@ -13,7 +20,11 @@
(let [dev? (= "true" (System/getenv "BABASHKA_DEV"))
opts (merge {:debug dev?
:describe {"versions" {"babashka" common/version}}
- :thread-bind [babashka.impl.clojure.core/warn-on-reflection]}
+ :thread-bind [core-extras/warn-on-reflection
+ core-extras/unchecked-math
+ core-extras/data-readers
+ sci/ns
+ sci/print-length]}
opts)]
(server/start-server! (common/ctx) opts))))
diff --git a/src/babashka/impl/print_deps.clj b/src/babashka/impl/print_deps.clj
index 0e9d0288..593fd836 100644
--- a/src/babashka/impl/print_deps.clj
+++ b/src/babashka/impl/print_deps.clj
@@ -14,11 +14,11 @@
edn/read-string)
deps (:deps deps)
deps (assoc deps
- 'babashka/fs {:mvn/version "0.2.12"}
+ 'babashka/fs {:mvn/version "0.4.19"}
'babashka/babashka.curl {:mvn/version "0.1.2"}
'babashka/babashka.core {:git/url "https://github.com/babashka/babashka.core"
:git/sha "52a6037bd4b632bffffb04394fb4efd0cdab6b1e"}
- 'babashka/process {:mvn/version "0.4.13"})
+ 'babashka/process {:mvn/version "0.5.21"})
deps (dissoc deps
'borkdude/sci
'org.babashka/sci
@@ -30,6 +30,7 @@
'org.hsqldb/hsqldb)
bb-edn-deps (:deps @common/bb-edn)
deps (merge deps bb-edn-deps)
+ deps (into (sorted-map) deps)
paths (:paths @common/bb-edn)
deps {:deps deps}
deps (cond-> deps
diff --git a/src/babashka/impl/process.clj b/src/babashka/impl/process.clj
index 33d77ea3..a931e23c 100644
--- a/src/babashka/impl/process.clj
+++ b/src/babashka/impl/process.clj
@@ -20,6 +20,18 @@
(binding [process/*defaults* @defaults]
(apply process/pb args)))
+(defn sh [& args]
+ (binding [process/*defaults* @defaults]
+ (apply process/sh args)))
+
+(defn shell [& args]
+ (binding [process/*defaults* @defaults]
+ (apply process/shell args)))
+
+(defn exec [& args]
+ (binding [process/*defaults* @defaults]
+ (apply process/exec args)))
+
(def process-namespace
{'parse-args (copy-var process/parse-args tns)
'process* (copy-var process/process* tns)
@@ -29,11 +41,11 @@
'start (copy-var process/start tns)
'pipeline (copy-var process/pipeline tns)
'$ (copy-var process/$ tns)
- 'sh (copy-var process/sh tns)
+ 'sh (copy-var sh tns)
'tokenize (copy-var process/tokenize tns)
'*defaults* defaults
'destroy (copy-var process/destroy tns)
'destroy-tree (copy-var process/destroy-tree tns)
- 'exec (copy-var process/exec tns)
- 'shell (copy-var process/shell tns)
+ 'exec (copy-var exec tns)
+ 'shell (copy-var shell tns)
'alive? (copy-var process/alive? tns)})
diff --git a/src/babashka/impl/proxy.clj b/src/babashka/impl/proxy.clj
index f40b7ab1..7e4ad722 100644
--- a/src/babashka/impl/proxy.clj
+++ b/src/babashka/impl/proxy.clj
@@ -100,6 +100,36 @@
(write
([b] ((method-or-bust methods 'write) this b))
([b off len] ((method-or-bust methods 'write) this b off len))))
+
+ ["java.io.OutputStream" #{}]
+ (proxy [java.io.OutputStream] []
+ (close [] (when-let [m (get methods 'close)]
+ (m this)))
+ (flush [] (when-let [m (get methods 'flush)]
+ (m this)))
+ (write
+ ([b]
+ ((method-or-bust methods 'write) this b))
+ ([b off len]
+ ((method-or-bust methods 'write) this b off len))))
+ ["javax.net.ssl.X509ExtendedTrustManager" #{}]
+ (proxy [javax.net.ssl.X509ExtendedTrustManager] []
+ (checkClientTrusted
+ ([x y]
+ ((method-or-bust methods 'checkClientTrusted) this x y))
+ ([x y z]
+ ((method-or-bust methods 'checkClientTrusted) this x y z)))
+ (checkServerTrusted
+ ([x y]
+ ((method-or-bust methods 'checkServerTrusted) this x y))
+ ([x y z]
+ ((method-or-bust methods 'checkServerTrusted) this x y z)))
+ (getAcceptedIssuers [] ((method-or-bust methods 'getAcceptedIssuers) this)))
+
+ ["java.lang.ThreadLocal" #{}]
+ (proxy [java.lang.ThreadLocal] []
+ (initialValue []
+ ((method-or-bust methods 'initialValue) this)))
, ;; keep this for merge friendliness
)))
@@ -112,7 +142,9 @@
{:methods [{:name "connectFailed"}
{:name "select"}]}
(class-sym (class (proxy-fn {:class javax.net.ssl.HostnameVerifier})))
- {:methods [{:name "verify"}]}})
+ {:methods [{:name "verify"}]}
+ (class-sym (class (proxy-fn {:class java.lang.ThreadLocal})))
+ {:methods [{:name "get"}]}})
;;; Scratch
diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj
index 11dcf370..86fd58e6 100644
--- a/src/babashka/impl/repl.clj
+++ b/src/babashka/impl/repl.clj
@@ -1,6 +1,7 @@
(ns babashka.impl.repl
{:no-doc true}
(:require
+ [babashka.impl.clojure.core :as core-extras]
[babashka.impl.clojure.main :as m]
[clojure.java.io :as io]
[clojure.string :as str]
@@ -50,41 +51,46 @@
([sci-ctx] (repl sci-ctx nil))
([sci-ctx {:keys [:init :read :eval :need-prompt :prompt :flush :print :caught]}]
(let [in @sci/in]
- (m/repl
- :init (or init
- (fn []
- (sci/with-bindings {sci/out @sci/err}
- (sio/println "Babashka"
- (str "v" (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
- "REPL.")
- (sio/println "Use :repl/quit or :repl/exit to quit the REPL.")
- (sio/println "Clojure rocks, Bash reaches.")
- (sio/println))
- (eval-form sci-ctx `(apply require (quote ~m/repl-requires)))))
- :read (or read
- (fn [_request-prompt request-exit]
- (if (nil? (r/peek-char in))
- request-exit
- (let [v (parser/parse-next sci-ctx in)]
- (skip-if-eol in)
- (if (or (identical? :repl/quit v)
- (identical? :repl/exit v))
- request-exit
- v)))))
- :eval (or eval
- (fn [expr]
- (sci/with-bindings {sci/file ""
- sci/*1 *1
- sci/*2 *2
- sci/*3 *3
- sci/*e *e}
- (let [ret (eval-form sci-ctx expr)]
- ret))))
- :need-prompt (or need-prompt (fn [] true))
- :prompt (or prompt #(sio/printf "%s=> " (utils/current-ns-name)))
- :flush (or flush sio/flush)
- :print (or print sio/prn)
- :caught (or caught repl-caught)))))
+ (sci/binding [core-extras/warn-on-reflection @core-extras/warn-on-reflection
+ core-extras/unchecked-math @core-extras/unchecked-math
+ core-extras/data-readers @core-extras/data-readers
+ sci/ns @sci/ns
+ sci/print-length @sci/print-length]
+ (m/repl
+ :init (or init
+ (fn []
+ (sci/with-bindings {sci/out @sci/err}
+ (sio/println "Babashka"
+ (str "v" (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
+ "REPL.")
+ (sio/println "Use :repl/quit or :repl/exit to quit the REPL.")
+ (sio/println "Clojure rocks, Bash reaches.")
+ (sio/println))
+ (eval-form sci-ctx `(apply require (quote ~m/repl-requires)))))
+ :read (or read
+ (fn [_request-prompt request-exit]
+ (if (nil? (r/peek-char in))
+ request-exit
+ (let [v (parser/parse-next sci-ctx in)]
+ (skip-if-eol in)
+ (if (or (identical? :repl/quit v)
+ (identical? :repl/exit v))
+ request-exit
+ v)))))
+ :eval (or eval
+ (fn [expr]
+ (sci/with-bindings {sci/file ""
+ sci/*1 *1
+ sci/*2 *2
+ sci/*3 *3
+ sci/*e *e}
+ (let [ret (eval-form sci-ctx expr)]
+ ret))))
+ :need-prompt (or need-prompt (fn [] true))
+ :prompt (or prompt #(sio/printf "%s=> " (utils/current-ns-name)))
+ :flush (or flush sio/flush)
+ :print (or print sio/prn)
+ :caught (or caught repl-caught))))))
(defn start-repl!
([sci-ctx] (start-repl! sci-ctx nil))
diff --git a/src/babashka/impl/sci.clj b/src/babashka/impl/sci.clj
new file mode 100644
index 00000000..b930a418
--- /dev/null
+++ b/src/babashka/impl/sci.clj
@@ -0,0 +1,52 @@
+(ns babashka.impl.sci
+ {:no-doc true}
+ (:require [sci.core :as sci]
+ [sci.ctx-store :as store]))
+
+(def sns (sci/create-ns 'sci.core nil))
+
+(defmacro copy-ns
+ "Returns map of names to SCI vars as a result of copying public
+ Clojure vars from ns-sym (a symbol). Attaches sci-ns (result of
+ sci/create-ns) to meta. Copies :name, :macro :doc, :no-doc
+ and :argslists metadata.
+
+ Options:
+
+ - :exclude: a seqable of names to exclude from the
+ namespace. Defaults to none.
+
+ - :copy-meta: a seqable of keywords to copy from the original var
+ meta. Use :all instead of a seqable to copy all. Defaults
+ to [:doc :arglists :macro].
+
+ - :exclude-when-meta: seqable of keywords; vars with meta matching
+ these keys are excluded. Defaults to [:no-doc :skip-wiki]
+
+ The selection of vars is done at compile time which is mostly
+ important for ClojureScript to not pull in vars into the compiled
+ JS. Any additional vars can be added after the fact with sci/copy-var
+ manually."
+ ([ns-sym sci-ns] `(sci.core/copy-ns ~ns-sym ~sci-ns nil))
+ ([ns-sym sci-ns opts]
+ ;; this branch is hit by macroexpanding in JVM Clojure, not in the CLJS compiler
+ (let [publics-map (sci/eval-form (store/get-ctx) (list 'ns-publics (list 'quote ns-sym)))
+ publics-map (#'sci/process-publics publics-map opts)
+ mf (#'sci/meta-fn (:copy-meta opts))
+ publics-map (#'sci/exclude-when-meta
+ publics-map
+ meta
+ (fn [k]
+ (list 'quote k))
+ (fn [var m]
+ {:name (list 'quote (:name m))
+ :var var
+ :meta (list 'quote (mf m))})
+ (or (:exclude-when-meta opts)
+ [:no-doc :skip-wiki]))]
+ `(sci.core/-copy-ns ~publics-map ~sci-ns))))
+
+(def sci-core-namespace
+ (assoc (sci/copy-ns sci.core sns {:exclude [copy-ns]})
+ 'copy-ns (sci/copy-var copy-ns sns)
+ '-copy-ns (sci/copy-var sci/-copy-ns sns)))
diff --git a/src/babashka/impl/tasks.clj b/src/babashka/impl/tasks.clj
index f2775b8f..3fe45785 100644
--- a/src/babashka/impl/tasks.clj
+++ b/src/babashka/impl/tasks.clj
@@ -6,7 +6,6 @@
[babashka.impl.process :as pp]
[babashka.process :as p]
[clojure.core.async :refer [ args
+ cmd (->> (cons cmd)))
local-log-level (:log-level opts)]
(sci/binding [log-level (or local-log-level @log-level)]
(apply log-info (cons "clojure" cmd))
- (handle-non-zero (deps/clojure cmd (merge default-opts opts)) opts))))
+ (handle-non-zero (apply deps/clojure (merge default-opts opts) cmd) opts))))
(defn -wait [res]
(when res
@@ -139,7 +127,7 @@
"Used internally for debugging"
[& strs]
(locking o
- (apply prn strs)))
+ (apply prn strs)))
(defn wait-tasks [deps]
(if deps
@@ -397,7 +385,7 @@
loc (zip/down loc)]
(into []
(comp
- (take-nth 2 )
+ (take-nth 2)
(take-while #(not (zip/end? %)))
(filter zip/sexpr-able?)
(map zip/sexpr)
@@ -437,8 +425,11 @@
([task] (run task nil))
([task {:keys [:parallel]
:or {parallel (:parallel (current-task))}}]
- (let [[[expr]] (assemble-task task parallel)]
- (sci/eval-string* (ctx) expr))))
+ (let [[[expr] exit-code] (assemble-task task parallel)]
+ (if (or (nil? exit-code) (zero? exit-code))
+ (sci/eval-string* (ctx) expr)
+ (throw (ex-info nil
+ {:babashka/exit exit-code}))))))
(defn exec
([sym]
diff --git a/src/babashka/main.clj b/src/babashka/main.clj
index 6d117011..9626a9c0 100644
--- a/src/babashka/main.clj
+++ b/src/babashka/main.clj
@@ -19,13 +19,14 @@
[babashka.impl.clojure.java.shell :refer [shell-namespace]]
[babashka.impl.clojure.main :as clojure-main :refer [demunge]]
[babashka.impl.clojure.math :refer [math-namespace]]
+ [babashka.impl.clojure.reflect :refer [reflect-namespace]]
[babashka.impl.clojure.stacktrace :refer [stacktrace-namespace]]
[babashka.impl.clojure.tools.reader :refer [reader-namespace]]
[babashka.impl.clojure.tools.reader-types :refer [edn-namespace
reader-types-namespace]]
[babashka.impl.clojure.zip :refer [zip-namespace]]
[babashka.impl.common :as common]
- [babashka.impl.core :as bbcore]
+ [babashka.impl.core :as bbcore]
[babashka.impl.curl :refer [curl-namespace]]
[babashka.impl.data :as data]
[babashka.impl.datafy :refer [datafy-namespace]]
@@ -34,6 +35,7 @@
[babashka.impl.error-handler :refer [error-handler]]
[babashka.impl.features :as features]
[babashka.impl.fs :refer [fs-namespace]]
+ [babashka.impl.http-client :refer [http-client-namespace http-client-websocket-namespace]]
[babashka.impl.nrepl-server :refer [nrepl-server-namespace]]
[babashka.impl.pods :as pods]
[babashka.impl.pprint :refer [pprint-namespace]]
@@ -44,6 +46,7 @@
[babashka.impl.reify2 :refer [reify-fn]]
[babashka.impl.repl :as repl]
[babashka.impl.rewrite-clj :as rewrite]
+ [babashka.impl.sci :refer [sci-core-namespace]]
[babashka.impl.server :refer [clojure-core-server-namespace]]
[babashka.impl.socket-repl :as socket-repl]
[babashka.impl.tasks :as tasks :refer [tasks-namespace]]
@@ -55,6 +58,7 @@
[clojure.edn :as edn]
[clojure.java.io :as io]
[clojure.string :as str]
+ [edamame.core :as edamame]
[hf.depstar.uberjar :as uberjar]
[sci.addons :as addons]
[sci.core :as sci]
@@ -62,6 +66,7 @@
[sci.impl.copy-vars :as sci-copy-vars]
[sci.impl.io :as sio]
[sci.impl.namespaces :as sci-namespaces]
+ [sci.impl.parser]
[sci.impl.types :as sci-types]
[sci.impl.unrestrict :refer [*unrestricted*]]
[sci.impl.vars :as vars])
@@ -139,6 +144,7 @@
(println "
Usage: bb [svm-opts] [global-opts] [eval opts] [cmdline args]
or: bb [svm-opts] [global-opts] file [cmdline args]
+or: bb [svm-opts] [global-opts] task [cmdline args]
or: bb [svm-opts] [global-opts] subcommand [subcommand opts] [cmdline args]
Substrate VM opts:
@@ -151,10 +157,13 @@ Global opts:
-cp, --classpath Classpath to use. Overrides bb.edn classpath.
--debug Print debug information and internal stacktrace in case of exception.
--init Load file after any preloads and prior to evaluation/subcommands.
- --config Replacing bb.edn with file. Relative paths are resolved relative to file.
+ --config Replace bb.edn with file. Defaults to bb.edn adjacent to invoked file or bb.edn in current dir. Relative paths are resolved relative to bb.edn.
--deps-root Treat dir as root of relative paths in config.
+ --prn Print result via clojure.core/prn
-Sforce Force recalculation of the classpath (don't use the cache)
-Sdeps Deps data to use as the last deps file to be merged
+ -f, --file Run file
+ --jar Run uberjar
Help:
@@ -166,7 +175,6 @@ Help:
Evaluation:
-e, --eval Evaluate an expression.
- -f, --file Evaluate a file.
-m, --main Call the -main function from a namespace or call a fully qualified var.
-x, --exec Call the fully qualified var. Args are parsed by babashka CLI.
@@ -232,8 +240,7 @@ When no eval opts or subcommand is provided, the implicit subcommand is repl.")
(clojure.repl/doc %1$s)
true)" arg)))
[nil 0]
- [nil 1]))
- ,)
+ [nil 1])))
(defn print-run-help []
(println (str/trim "
@@ -320,25 +327,25 @@ Use bb run --help to show this help output.
(def aliases
(cond->
- '{str clojure.string
- set clojure.set
- tools.cli clojure.tools.cli
- edn clojure.edn
- wait babashka.wait
- signal babashka.signal
- shell clojure.java.shell
- io clojure.java.io
- json cheshire.core
- curl babashka.curl
- fs babashka.fs
- bencode bencode.core
- deps babashka.deps
- async clojure.core.async}
- features/xml? (assoc 'xml 'clojure.data.xml)
- features/yaml? (assoc 'yaml 'clj-yaml.core)
- features/jdbc? (assoc 'jdbc 'next.jdbc)
- features/csv? (assoc 'csv 'clojure.data.csv)
- features/transit? (assoc 'transit 'cognitect.transit)))
+ '{str clojure.string
+ set clojure.set
+ tools.cli clojure.tools.cli
+ edn clojure.edn
+ wait babashka.wait
+ signal babashka.signal
+ shell clojure.java.shell
+ io clojure.java.io
+ json cheshire.core
+ curl babashka.curl
+ fs babashka.fs
+ bencode bencode.core
+ deps babashka.deps
+ async clojure.core.async}
+ features/xml? (assoc 'xml 'clojure.data.xml)
+ features/yaml? (assoc 'yaml 'clj-yaml.core)
+ features/jdbc? (assoc 'jdbc 'next.jdbc)
+ features/csv? (assoc 'csv 'clojure.data.csv)
+ features/transit? (assoc 'transit 'cognitect.transit)))
;;(def ^:private server-ns-obj (sci/create-ns 'clojure.core.server nil))
@@ -349,85 +356,85 @@ Use bb run --help to show this help output.
(defn catvec [& xs]
(into [] cat xs))
-(def sci-ns (sci/create-ns 'sci.core))
+(def main-var (sci/new-var 'main nil {:ns clojure-main-ns}))
(require '[clojure.reflect] '[clojure.core.memoize :as memoize])
(def namespaces
(cond->
- {'user {'*input* (reify
- sci-types/Eval
- (eval [_ _ctx _bindings]
- (force @input-var)))}
- 'clojure.tools.cli tools-cli-namespace
- 'clojure.java.shell shell-namespace
- 'babashka.core bbcore/core-namespace
- 'babashka.nrepl.server nrepl-server-namespace
- 'babashka.wait wait-namespace
- 'babashka.signal signal-ns
- 'clojure.java.io io-namespace
- 'cheshire.core cheshire-core-namespace
- 'clojure.data data/data-namespace
- 'clojure.instant instant/instant-namespace
- 'clojure.stacktrace stacktrace-namespace
- 'clojure.zip zip-namespace
- 'clojure.main {:obj clojure-main-ns
- 'demunge (sci/copy-var demunge clojure-main-ns)
- 'repl-requires (sci/copy-var clojure-main/repl-requires clojure-main-ns)
- 'repl (sci/new-var 'repl
- (fn [& opts]
- (let [opts (apply hash-map opts)]
- (repl/start-repl! (common/ctx) opts))) {:ns clojure-main-ns})
- 'with-bindings (sci/copy-var clojure-main/with-bindings clojure-main-ns)}
- 'clojure.test t/clojure-test-namespace
- 'clojure.math math-namespace
- 'babashka.classpath classpath-namespace
- 'babashka.classes classes-namespace
- 'clojure.pprint pprint-namespace
- 'babashka.curl curl-namespace
- 'babashka.fs fs-namespace
- 'babashka.pods pods/pods-namespace
- 'bencode.core bencode-namespace
- 'clojure.java.browse browse-namespace
- 'clojure.datafy datafy-namespace
- 'clojure.core.protocols protocols-namespace
- 'babashka.process process-namespace
- 'clojure.core.server clojure-core-server-namespace
- 'babashka.deps deps-namespace
- 'babashka.tasks tasks-namespace
- 'clojure.tools.reader.edn edn-namespace
- 'clojure.tools.reader.reader-types reader-types-namespace
- 'clojure.tools.reader reader-namespace
- 'clojure.core.async async-namespace
- 'clojure.core.async.impl.protocols async-protocols-namespace
- 'rewrite-clj.node rewrite/node-namespace
- 'rewrite-clj.paredit rewrite/paredit-namespace
- 'rewrite-clj.parser rewrite/parser-namespace
- 'rewrite-clj.zip rewrite/zip-namespace
- 'rewrite-clj.zip.subedit rewrite/subedit-namespace
- 'clojure.core.rrb-vector (if features/rrb-vector?
- @(resolve 'babashka.impl.rrb-vector/rrb-vector-namespace)
- {'catvec (sci/copy-var catvec
- (sci/create-ns 'clojure.core.rrb-vector))})
- 'edamame.core edamame-namespace
- 'sci.core {'format-stacktrace (sci/copy-var sci/format-stacktrace sci-ns)
- 'stacktrace (sci/copy-var sci/stacktrace sci-ns)
- ;; 'eval-string (sci/copy-var sci/eval-string sci-ns)
- ;; 'eval-string* (sci/copy-var sci/eval-string* sci-ns)
- ;; 'init (sci/copy-var sci/init sci-ns)
- ;; 'fork (sci/copy-var sci/fork sci-ns)
- }
- 'babashka.cli cli/cli-namespace
- }
- features/xml? (assoc 'clojure.data.xml @(resolve 'babashka.impl.xml/xml-namespace)
- 'clojure.data.xml.event @(resolve 'babashka.impl.xml/xml-event-namespace)
- 'clojure.data.xml.tree @(resolve 'babashka.impl.xml/xml-tree-namespace))
+ {'user {'*input* (reify
+ sci-types/Eval
+ (eval [_ _ctx _bindings]
+ (force @input-var)))}
+ 'clojure.core core-extras
+ 'clojure.tools.cli tools-cli-namespace
+ 'clojure.java.shell shell-namespace
+ 'babashka.core bbcore/core-namespace
+ 'babashka.nrepl.server nrepl-server-namespace
+ 'babashka.wait wait-namespace
+ 'babashka.signal signal-ns
+ 'clojure.java.io io-namespace
+ 'cheshire.core cheshire-core-namespace
+ 'clojure.data data/data-namespace
+ 'clojure.instant instant/instant-namespace
+ 'clojure.stacktrace stacktrace-namespace
+ 'clojure.zip zip-namespace
+ 'clojure.main {:obj clojure-main-ns
+ 'demunge (sci/copy-var demunge clojure-main-ns)
+ 'repl-requires (sci/copy-var clojure-main/repl-requires clojure-main-ns)
+ 'repl (sci/new-var 'repl
+ (fn [& opts]
+ (let [opts (apply hash-map opts)]
+ (repl/start-repl! (common/ctx) opts))) {:ns clojure-main-ns})
+ 'with-bindings (sci/copy-var clojure-main/with-bindings clojure-main-ns)
+ 'repl-caught (sci/copy-var repl/repl-caught clojure-main-ns)
+ 'main main-var}
+ 'clojure.test t/clojure-test-namespace
+ 'clojure.math math-namespace
+ 'babashka.classpath classpath-namespace
+ 'babashka.classes classes-namespace
+ 'clojure.pprint pprint-namespace
+ 'babashka.curl curl-namespace
+ 'babashka.fs fs-namespace
+ 'babashka.pods pods/pods-namespace
+ 'bencode.core bencode-namespace
+ 'clojure.java.browse browse-namespace
+ 'clojure.datafy datafy-namespace
+ 'clojure.core.protocols protocols-namespace
+ 'babashka.process process-namespace
+ 'clojure.core.server clojure-core-server-namespace
+ 'babashka.deps deps-namespace
+ 'babashka.tasks tasks-namespace
+ 'clojure.tools.reader.edn edn-namespace
+ 'clojure.tools.reader.reader-types reader-types-namespace
+ 'clojure.tools.reader reader-namespace
+ 'clojure.core.async async-namespace
+ 'clojure.core.async.impl.protocols async-protocols-namespace
+ 'clojure.reflect reflect-namespace
+ 'rewrite-clj.node rewrite/node-namespace
+ 'rewrite-clj.paredit rewrite/paredit-namespace
+ 'rewrite-clj.parser rewrite/parser-namespace
+ 'rewrite-clj.zip rewrite/zip-namespace
+ 'rewrite-clj.zip.subedit rewrite/subedit-namespace
+ 'clojure.core.rrb-vector (if features/rrb-vector?
+ @(resolve 'babashka.impl.rrb-vector/rrb-vector-namespace)
+ {'catvec (sci/copy-var catvec
+ (sci/create-ns 'clojure.core.rrb-vector))})
+ 'edamame.core edamame-namespace
+ 'sci.core sci-core-namespace
+ 'babashka.cli cli/cli-namespace
+ 'babashka.http-client http-client-namespace
+ 'babashka.http-client.websocket http-client-websocket-namespace}
+ features/xml? (assoc 'clojure.data.xml @(resolve 'babashka.impl.xml/xml-namespace)
+ 'clojure.data.xml.event @(resolve 'babashka.impl.xml/xml-event-namespace)
+ 'clojure.data.xml.tree @(resolve 'babashka.impl.xml/xml-tree-namespace))
features/yaml? (assoc 'clj-yaml.core @(resolve 'babashka.impl.yaml/yaml-namespace)
- 'flatland.ordered.map @(resolve 'babashka.impl.ordered/ordered-map-ns))
+ 'flatland.ordered.map @(resolve 'babashka.impl.ordered/ordered-map-ns)
+ 'flatland.ordered.set @(resolve 'babashka.impl.ordered/ordered-set-ns))
features/jdbc? (assoc 'next.jdbc @(resolve 'babashka.impl.jdbc/njdbc-namespace)
'next.jdbc.sql @(resolve 'babashka.impl.jdbc/next-sql-namespace)
'next.jdbc.result-set @(resolve 'babashka.impl.jdbc/result-set-namespace))
- features/csv? (assoc 'clojure.data.csv @(resolve 'babashka.impl.csv/csv-namespace))
+ features/csv? (assoc 'clojure.data.csv @(resolve 'babashka.impl.csv/csv-namespace))
features/transit? (assoc 'cognitect.transit @(resolve 'babashka.impl.transit/transit-namespace))
features/datascript? (assoc 'datascript.core @(resolve 'babashka.impl.datascript/datascript-namespace)
'datascript.db @(resolve 'babashka.impl.datascript/datascript-db-namespace))
@@ -455,8 +462,8 @@ Use bb run --help to show this help output.
@(resolve 'babashka.impl.clojure.test.check/test-check-namespace)
;; it's better to load this from source by adding the clojure.test.check dependency
#_#_'clojure.test.check.clojure-test
- @(resolve 'babashka.impl.clojure.test.check/test-check-clojure-test-namespace))
- features/spec-alpha? (-> (assoc ;; spec
+ @(resolve 'babashka.impl.clojure.test.check/test-check-clojure-test-namespace))
+ features/spec-alpha? (-> (assoc ;; spec
'clojure.spec.alpha @(resolve 'babashka.impl.spec/spec-namespace)
'clojure.spec.gen.alpha @(resolve 'babashka.impl.spec/gen-namespace)
'clojure.spec.test.alpha @(resolve 'babashka.impl.spec/test-namespace)))
@@ -471,6 +478,7 @@ Use bb run --help to show this help output.
'selmer.validator
@(resolve 'babashka.impl.selmer/selmer-validator-namespace))
features/logging? (assoc 'taoensso.timbre @(resolve 'babashka.impl.logging/timbre-namespace)
+ 'taoensso.timbre.appenders.core @(resolve 'babashka.impl.logging/timbre-appenders-namespace)
'clojure.tools.logging
@(resolve 'babashka.impl.logging/tools-logging-namespace)
'clojure.tools.logging.impl
@@ -487,7 +495,8 @@ Use bb run --help to show this help output.
(def edn-readers (cond-> {}
features/yaml?
- (assoc 'ordered/map @(resolve 'flatland.ordered.map/ordered-map))
+ (assoc 'ordered/map @(resolve 'flatland.ordered.map/ordered-map)
+ 'ordered/set @(resolve 'flatland.ordered.set/ordered-set))
features/xml?
(assoc 'xml/ns @(resolve 'clojure.data.xml.name/uri-symbol)
'xml/element @(resolve 'clojure.data.xml.node/tagged-element))))
@@ -575,10 +584,10 @@ Use bb run --help to show this help output.
:edn-in true))
("-o") (recur (next options)
(assoc opts-map
- :shell-out true))
+ :shell-out true :prn true))
("-O") (recur (next options)
(assoc opts-map
- :edn-out true))
+ :edn-out true :prn true))
("-io") (recur (next options)
(assoc opts-map
:shell-in true
@@ -609,16 +618,6 @@ Use bb run --help to show this help output.
(recur (next options)
(assoc opts-map
:uberjar (first options))))
- ("-f" "--file")
- (let [options (next options)]
- (recur (next options)
- (assoc opts-map
- :file (first options))))
- ("--jar" "-jar")
- (let [options (next options)]
- (recur (next options)
- (assoc opts-map
- :jar (first options))))
("--repl")
(let [options (next options)]
(recur (next options)
@@ -645,16 +644,17 @@ Use bb run --help to show this help output.
(assoc opts-map
:nrepl (or opt "1667"))))
("--eval", "-e")
- (let [options (next options)]
+ (let [options (next options)
+ opts-map (assoc opts-map :prn true)]
(recur (next options)
(update opts-map :expressions (fnil conj []) (first options))))
- ("--main", "-m",)
+ ("--main", "-m")
(let [options (next options)]
(assoc opts-map :main (first options)
:command-line-args (if (= "--" (second options))
(nthrest options 2)
(rest options))))
- ("--exec", "-x",)
+ ("--exec", "-x")
(let [options (next options)]
(assoc opts-map :exec (first options)
:command-line-args (if (= "--" (second options))
@@ -681,6 +681,7 @@ Use bb run --help to show this help output.
(case c
(\( \{ \[ \* \@ \#)
(-> opts-map
+ (assoc :prn true)
(update :expressions (fnil conj []) (first options))
(assoc :command-line-args (next options)))
(assoc opts-map
@@ -716,36 +717,49 @@ Use bb run --help to show this help output.
("--deps-root")
(recur (nnext options) (assoc opts-map :deps-root (second options)))
+ ("--prn")
+ (recur (next options) (assoc opts-map :prn true))
+ ("-f" "--file")
+ (recur (nnext options) (assoc opts-map :file (second options)))
+ ("-jar" "--jar")
+ (recur (nnext options) (assoc opts-map :jar (second options)))
[options opts-map])
[options opts-map])))
(defn parse-file-opt
[options opts-map]
- (let [opt (first options)
- opts-key (if (str/ends-with? opt ".jar")
- :jar :file)]
- (assoc opts-map
- opts-key opt
- :command-line-args (next options))))
+ (let [opt (first options)]
+ (if (and opt (and (fs/exists? opt)
+ (not (fs/directory? opt))))
+ [nil (assoc opts-map
+ (if (str/ends-with? opt ".jar")
+ :jar :file) opt
+ :command-line-args (next options))]
+ [options opts-map])))
(defn parse-opts
([options] (parse-opts options nil))
([options opts-map]
(let [opt (first options)
- tasks (into #{} (map str) (keys (:tasks @common/bb-edn)))]
+ task-map (:tasks @common/bb-edn)
+ tasks (into #{} (map str) (keys task-map))]
+ (when-let [commands (seq (filter (fn [task]
+ (and (command? task)
+ (not (:override-builtin (get task-map (symbol task))))))
+ tasks))]
+ (binding [*out* *err*]
+ (println "[babashka] WARNING: task(s)" (str/join ", " (map #(format "'%s'" %) commands)) "override built-in command(s). Use :override-builtin true to disable warning.")))
(if-not opt opts-map
;; FILE > TASK > SUBCOMMAND
(cond
- (.isFile (io/file opt))
- (if (or (:file opts-map) (:jar opts-map))
- opts-map ; we've already parsed the file opt
- (parse-file-opt options opts-map))
-
+ (and (not (or (:file opts-map)
+ (:jar opts-map)))
+ (.isFile (io/file opt)))
+ (parse-file-opt options opts-map)
(contains? tasks opt)
(assoc opts-map
:run opt
:command-line-args (next options))
-
(command? opt)
(recur (cons (str "--" opt) (next options)) opts-map)
@@ -775,13 +789,56 @@ Use bb run --help to show this help output.
env-os-name-present? (not= env-os-name sys-os-name)
env-os-arch-present? (not= env-os-arch sys-os-arch))))
+(defn file-write-allowed?
+ "For output file of uberscript/uberjar, allow writing of jar files
+ and files that are empty/don't exist."
+ [path]
+ (or (= "jar" (fs/extension path))
+ (not (fs/exists? path))))
+
+(def seen-urls (atom nil))
+
+(defn read-data-readers [url]
+ (edamame/parse-string (slurp url)
+ {:read-cond :allow
+ :features #{:bb :clj}
+ :eof nil}))
+
+(defn readers-fn
+ "Lazy reading of data reader functions"
+ [ctx t]
+ (or (@core/data-readers t)
+ (default-data-readers t)
+ (when (simple-symbol? t)
+ (when-let [the-var (sci/resolve ctx t)]
+ (some-> the-var meta :sci.impl.record/map-constructor)))
+ (when-let [f @sci.impl.parser/default-data-reader-fn]
+ (fn [form]
+ (f t form)))
+ (let [;; urls is a vector for equality check
+ urls (vec (.getURLs ^java.net.URLClassLoader @cp/the-url-loader))
+ parsed-resources (or (get @seen-urls urls)
+ (let [^java.net.URLClassLoader cl @cp/the-url-loader
+ resources (concat (enumeration-seq (.getResources cl "data_readers.clj"))
+ (enumeration-seq (.getResources cl "data_readers.cljc")))
+ parsed-resources (apply merge (map read-data-readers resources))
+ _ (swap! seen-urls assoc urls parsed-resources)]
+ parsed-resources))]
+ (when-let [var-sym (get parsed-resources t)]
+ (when-let [the-var (sci/resolve ctx var-sym)]
+ (sci/eval-form ctx (list 'clojure.core/var-set core/data-readers (list 'quote (assoc @core/data-readers t the-var))))
+ the-var)))))
+
(defn exec [cli-opts]
- (binding [*unrestricted* true]
+ (with-bindings {#'*unrestricted* true
+ clojure.lang.Compiler/LOADER @cp/the-url-loader}
(sci/binding [core/warn-on-reflection @core/warn-on-reflection
core/unchecked-math @core/unchecked-math
core/data-readers @core/data-readers
sci/ns @sci/ns
- sci/print-length @sci/print-length]
+ sci/print-length @sci/print-length
+ ;; when adding vars here, also add them to repl.clj and nrepl_server.clj
+ ]
(let [{version-opt :version
:keys [:shell-in :edn-in :shell-out :edn-out
:help :file :command-line-args
@@ -794,6 +851,7 @@ Use bb run --help to show this help output.
:print-deps :prepare]
exec-fn :exec}
cli-opts
+ print-result? (:prn cli-opts)
_ (when debug (vreset! common/debug true))
_ (do ;; set properties
(when main (System/setProperty "babashka.main" main))
@@ -828,15 +886,14 @@ Use bb run --help to show this help output.
abs-path))
_ (when jar
(cp/add-classpath jar))
- load-fn (fn [{:keys [:namespace :reload]}]
- (let [{:keys [loader]}
- @cp/cp-state]
+ load-fn (fn [{:keys [namespace reload ctx]}]
+ (let [loader @cp/the-url-loader]
(or
(when ;; ignore built-in namespaces when uberscripting, unless with :reload
- (and uberscript
- (not reload)
- (or (contains? namespaces namespace)
- (contains? sci-namespaces/namespaces namespace)))
+ (and uberscript
+ (not reload)
+ (or (contains? namespaces namespace)
+ (contains? sci-namespaces/namespaces namespace)))
"")
;; pod namespaces go before namespaces from source,
;; unless reload is used
@@ -873,19 +930,18 @@ Use bb run --help to show this help output.
clojure.core.specs.alpha
(binding [*out* *err*]
(println "[babashka] WARNING: clojure.core.specs.alpha is removed from the classpath, unless you explicitly add the dependency."))
- nil))))
+ (when-not (sci/find-ns ctx namespace)
+ (let [file (str/replace (namespace-munge namespace) "." "/")]
+ (throw (new java.io.FileNotFoundException (format "Could not locate %s.bb, %s.clj or %s.cljc on classpath." file file file)))))))))
main (if (and jar (not main))
(when-let [res (cp/getResource
- (cp/loader jar)
+ (cp/new-loader [jar])
["META-INF/MANIFEST.MF"] {:url? true})]
(cp/main-ns res))
main)
;; TODO: pull more of these values to compile time
opts {:aliases aliases
- :namespaces (-> namespaces
- (assoc 'clojure.core
- (assoc core-extras
- 'load-file (sci-copy-vars/new-var 'load-file load-file*))))
+ :namespaces (assoc-in namespaces ['clojure.core 'load-file] (sci-copy-vars/new-var 'load-file load-file*))
:env env
:features #{:bb :clj}
:classes @classes/class-map
@@ -894,13 +950,14 @@ Use bb run --help to show this help output.
:uberscript uberscript
;; :readers core/data-readers
:reify-fn reify-fn
- :proxy-fn proxy-fn}
+ :proxy-fn proxy-fn
+ :readers #(readers-fn (common/ctx) %)}
opts (addons/future opts)
sci-ctx (sci/init opts)
_ (ctx-store/reset-ctx! sci-ctx)
_ (when-let [pods (:pods @common/bb-edn)]
(when-let [pod-metadata (pods/load-pods-metadata
- pods {:download-only (download-only?)})]
+ pods {:download-only (download-only?)})]
(vreset! pod-namespaces pod-metadata)))
preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim))
[expressions exit-code]
@@ -929,7 +986,7 @@ Use bb run --help to show this help output.
:debug debug
:preloads preloads
:init init
- :loader (:loader @cp/cp-state)}))))
+ :loader @cp/the-url-loader}))))
expression (str/join " " expressions) ;; this might mess with the locations...
exit-code
;; handle preloads
@@ -943,7 +1000,7 @@ Use bb run --help to show this help output.
:debug debug
:preloads preloads
:init init
- :loader (:loader @cp/cp-state)})))))
+ :loader @cp/the-url-loader})))))
nil))
exit-code
;; handle --init
@@ -956,7 +1013,7 @@ Use bb run --help to show this help output.
:debug debug
:preloads preloads
:init init
- :loader (:loader @cp/cp-state)}))))
+ :loader @cp/the-url-loader}))))
nil))
;; socket REPL is start asynchronously. when no other args are
;; provided, a normal REPL will be started as well, which causes the
@@ -999,8 +1056,7 @@ Use bb run --help to show this help output.
(sci/eval-string* sci-ctx expression))]
;; return value printing
(when (and (some? res)
- (or (not run)
- (:prn cli-opts)))
+ print-result?)
(if-let [pr-f (cond shell-out println
edn-out sio/prn)]
(if (sequential? res)
@@ -1016,7 +1072,7 @@ Use bb run --help to show this help output.
(error-handler e {:expression expression
:debug debug
:preloads preloads
- :loader (:loader @cp/cp-state)}))))
+ :loader @cp/the-url-loader}))))
clojure [nil (if-let [proc (bdeps/clojure command-line-args)]
(-> @proc :exit)
0)]
@@ -1024,29 +1080,38 @@ Use bb run --help to show this help output.
1)]
(flush)
(when uberscript
- (let [uberscript-out uberscript]
- (spit uberscript-out "") ;; reset file
- (doseq [s (distinct @uberscript-sources)]
- (spit uberscript-out s :append true))
- (spit uberscript-out preloads :append true)
- (spit uberscript-out expression :append true)))
+ (if (file-write-allowed? uberscript)
+ (do
+ (spit uberscript "") ;; reset file
+ (doseq [s (distinct @uberscript-sources)]
+ (spit uberscript s :append true))
+ (spit uberscript preloads :append true)
+ (spit uberscript expression :append true))
+ (throw (Exception. (str "Uberscript target file '" uberscript
+ "' exists and is not empty. Overwrite prohibited.")))))
(when uberjar
- (if-let [cp (cp/get-classpath)]
- (let [uber-params {:dest uberjar
- :jar :uber
- :classpath cp
- :main-class main
- :verbose debug}]
- (if-let [bb-edn-pods (:pods @common/bb-edn)]
- (fs/with-temp-dir [bb-edn-dir {}]
- (let [bb-edn-resource (fs/file bb-edn-dir "META-INF" "bb.edn")]
- (fs/create-dirs (fs/parent bb-edn-resource))
- (->> {:pods bb-edn-pods} pr-str (spit bb-edn-resource))
- (let [cp-with-bb-edn (str bb-edn-dir cp/path-sep cp)]
- (uberjar/run (assoc uber-params
- :classpath cp-with-bb-edn)))))
- (uberjar/run uber-params)))
- (throw (Exception. "The uberjar task needs a classpath."))))
+ (let [cp (cp/get-classpath)]
+ (cond
+ (not (file-write-allowed? uberjar))
+ (throw (Exception. (str "Uberjar target file '" uberjar
+ "' exists and is not empty. Overwrite prohibited.")))
+ (not cp)
+ (throw (Exception. "The uberjar task needs a classpath."))
+ :else
+ (let [uber-params {:dest uberjar
+ :jar :uber
+ :classpath cp
+ :main-class main
+ :verbose debug}]
+ (if-let [bb-edn-pods (:pods @common/bb-edn)]
+ (fs/with-temp-dir [bb-edn-dir {}]
+ (let [bb-edn-resource (fs/file bb-edn-dir "META-INF" "bb.edn")]
+ (fs/create-dirs (fs/parent bb-edn-resource))
+ (->> {:pods bb-edn-pods} pr-str (spit bb-edn-resource))
+ (let [cp-with-bb-edn (str bb-edn-dir cp/path-sep cp)]
+ (uberjar/run (assoc uber-params
+ :classpath cp-with-bb-edn)))))
+ (uberjar/run uber-params))))))
exit-code))))
(defn satisfies-min-version? [min-version]
@@ -1058,8 +1123,8 @@ Use bb run --help to show this help output.
(and (= minor-current minor-min)
(>= patch-current patch-min)))))))
-(defn load-bb-edn [string]
- (try (edn/read-string {:default tagged-literal} string)
+(defn read-bb-edn [string]
+ (try (edn/read-string {:default tagged-literal :eof nil} string)
(catch java.lang.RuntimeException e
(if (re-find #"No dispatch macro for: \"" (.getMessage e))
(throw (ex-info "Invalid regex literal found in EDN config, use re-pattern instead" {}))
@@ -1067,40 +1132,85 @@ Use bb run --help to show this help output.
(println "Error during loading bb.edn:"))
(throw e))))))
+(defn binary-invoked-as-jar []
+ (and (= "executable" (System/getProperty "org.graalvm.nativeimage.kind"))
+ (let [bin (-> (java.lang.ProcessHandle/current)
+ .info
+ .command
+ .get)
+ fn (fs/file-name bin)]
+ (if (= "bb" fn)
+ false
+ (if (and (fs/windows?)
+ (= "bb.exe" fn))
+ false
+ (when (try (with-open [_ (java.util.zip.ZipFile. (fs/file bin))])
+ true
+ (catch Exception _ false))
+ bin))))))
+
+(defn resolve-symbolic-link [f]
+ (if (and f (fs/exists? f))
+ (str (fs/real-path f))
+ f))
+
(defn main [& args]
- (let [[args global-opts] (parse-global-opts args)
- {:keys [:jar] :as file-opt} (when (some-> args first io/file .isFile)
- (parse-file-opt args global-opts))
- config (:config global-opts)
- merge-deps (:merge-deps global-opts)
- abs-path #(-> % io/file .getAbsolutePath)
- bb-edn-file (cond
- config (when (fs/exists? config) (abs-path config))
- jar (some-> jar cp/loader (cp/resource "META-INF/bb.edn") .toString)
- :else (when (fs/exists? "bb.edn") (abs-path "bb.edn")))
- bb-edn (when (or bb-edn-file merge-deps)
- (when bb-edn-file (System/setProperty "babashka.config" bb-edn-file))
- (let [raw-string (when bb-edn-file (slurp bb-edn-file))
- edn (when bb-edn-file (load-bb-edn raw-string))
+ (let [bin-jar (binary-invoked-as-jar)
+ args (if bin-jar
+ (list* "--jar" bin-jar "--" args)
+ args)
+ [args opts] (parse-global-opts args)
+ [args {:keys [config merge-deps debug] :as opts}]
+ (if-not (or (:file opts)
+ (:jar opts))
+ (parse-file-opt args opts)
+ [args opts])
+ {:keys [jar file]} opts
+ abs-path resolve-symbolic-link
+ config (cond
+ config (if (fs/exists? config) (abs-path config)
+ (when debug
+ (binding [*out* *err*]
+ (println "[babashka] WARNING: config file does not exist:" config))
+ nil))
+ jar (let [jar (resolve-symbolic-link jar)]
+ (some-> [jar] cp/new-loader (cp/resource "META-INF/bb.edn") .toString))
+ :else (if (and file (fs/exists? file))
+ ;; file relative to bb.edn
+ (let [file (abs-path file) ;; follow symlink
+ rel-bb-edn (fs/file (fs/parent file) "bb.edn")]
+ (if (fs/exists? rel-bb-edn)
+ (abs-path rel-bb-edn)
+ ;; fall back to local bb.edn
+ (when (fs/exists? "bb.edn")
+ (abs-path "bb.edn"))))
+ ;; default to local bb.edn
+ (when (fs/exists? "bb.edn")
+ (abs-path "bb.edn"))))
+ bb-edn (when (or config merge-deps)
+ (when config (System/setProperty "babashka.config" config))
+ (let [raw-string (when config (slurp config))
+ edn (when config (read-bb-edn raw-string))
edn (if merge-deps
- (deps/merge-deps [edn (load-bb-edn merge-deps)])
+ (deps/merge-deps [edn (read-bb-edn merge-deps)])
edn)
edn (assoc edn
:raw raw-string
- :file bb-edn-file)
- edn (if-let [deps-root (or (:deps-root global-opts)
+ :file config)
+ edn (if-let [deps-root (or (:deps-root opts)
(some-> config fs/parent))]
(assoc edn :deps-root deps-root)
edn)]
(vreset! common/bb-edn edn)))
- ;; _ (.println System/err (str bb-edn))
+ opts (parse-opts args opts)
min-bb-version (:min-bb-version bb-edn)]
+ (System/setProperty "java.class.path" "")
(when min-bb-version
(when-not (satisfies-min-version? min-bb-version)
(binding [*out* *err*]
(println (str "WARNING: this project requires babashka "
min-bb-version " or newer, but you have: " version)))))
- (exec (parse-opts args (merge global-opts file-opt)))))
+ (exec opts)))
(def musl?
"Captured at compile time, to know if we are running inside a
@@ -1139,6 +1249,7 @@ Use bb run --help to show this help output.
(let [exit-code (run args)]
(System/exit exit-code))))
+(sci/alter-var-root main-var (constantly -main))
;;;; Scratch
(comment)
diff --git a/test-resources/adjacent_bb/bb.edn b/test-resources/adjacent_bb/bb.edn
new file mode 100644
index 00000000..72cb21ec
--- /dev/null
+++ b/test-resources/adjacent_bb/bb.edn
@@ -0,0 +1,2 @@
+{:deps {medley/medley {:mvn/version "1.3.0"}
+ my-local/dep {:local/root "../local-dep"}}}
diff --git a/test-resources/adjacent_bb/medley.bb b/test-resources/adjacent_bb/medley.bb
new file mode 100755
index 00000000..e0f63c78
--- /dev/null
+++ b/test-resources/adjacent_bb/medley.bb
@@ -0,0 +1,10 @@
+#!/usr/bin/env bb
+
+(require '[local-dep])
+
+(assert (= :foo local-dep/local-dep-var))
+
+(ns medley
+ (:require [medley.core :as medley]))
+
+(prn (medley/index-by :id [{:id 1}]))
diff --git a/test-resources/babashka/exec_test.clj b/test-resources/babashka/exec_test.clj
index a18676bf..d68ab185 100644
--- a/test-resources/babashka/exec_test.clj
+++ b/test-resources/babashka/exec_test.clj
@@ -2,7 +2,9 @@
{:org.babashka/cli {:coerce {:foo []}}})
(defn exec-test
- {:org.babashka/cli {:coerce {:bar :keyword}}}
+ {:org.babashka/cli
+ {:exec-args {:foo :foo}
+ :coerce {:bar :keyword}}}
[m]
(if (:meta m)
(prn (meta m))
diff --git a/test-resources/babashka/src_for_classpath_test/data_readers.clj b/test-resources/babashka/src_for_classpath_test/data_readers.clj
new file mode 100644
index 00000000..bd963623
--- /dev/null
+++ b/test-resources/babashka/src_for_classpath_test/data_readers.clj
@@ -0,0 +1 @@
+{r/reverse reader/reversev}
diff --git a/test-resources/babashka/src_for_classpath_test/data_readers.cljc b/test-resources/babashka/src_for_classpath_test/data_readers.cljc
new file mode 100644
index 00000000..26a070c1
--- /dev/null
+++ b/test-resources/babashka/src_for_classpath_test/data_readers.cljc
@@ -0,0 +1 @@
+{r/distinct reader/distinctv}
diff --git a/test-resources/babashka/src_for_classpath_test/reader.clj b/test-resources/babashka/src_for_classpath_test/reader.clj
new file mode 100644
index 00000000..8e4b0c26
--- /dev/null
+++ b/test-resources/babashka/src_for_classpath_test/reader.clj
@@ -0,0 +1,7 @@
+(ns reader)
+
+(defn reversev [data]
+ (vec (reverse data)))
+
+(defn distinctv [data]
+ (vec (distinct data)))
diff --git a/test-resources/babashka/uberjar/src/my/main_main.clj b/test-resources/babashka/uberjar/src/my/main_main.clj
index 238d2b52..fb7dca4e 100644
--- a/test-resources/babashka/uberjar/src/my/main_main.clj
+++ b/test-resources/babashka/uberjar/src/my/main_main.clj
@@ -1,6 +1,6 @@
(ns my.main-main
(:require [my.impl :as impl])
- (:require [my.impl2 :as impl2]))
+ (:require [my.impl2]))
(defn -main [& args]
- (impl/impl-fn args))
+ (prn (impl/impl-fn args)))
diff --git a/test-resources/bb_in_root_script_in_other_dir/bb.edn b/test-resources/bb_in_root_script_in_other_dir/bb.edn
new file mode 100644
index 00000000..573466cb
--- /dev/null
+++ b/test-resources/bb_in_root_script_in_other_dir/bb.edn
@@ -0,0 +1,2 @@
+{:deps {medley/medley {:mvn/version "1.3.0"}}}
+
diff --git a/test-resources/bb_in_root_script_in_other_dir/dir/script.clj b/test-resources/bb_in_root_script_in_other_dir/dir/script.clj
new file mode 100755
index 00000000..c28aa58d
--- /dev/null
+++ b/test-resources/bb_in_root_script_in_other_dir/dir/script.clj
@@ -0,0 +1,6 @@
+#!/usr/bin/env bb
+
+(ns script
+ (:require [medley.core :as medley]))
+
+(prn (medley/index-by :id [{:id 1}]))
diff --git a/test-resources/certificate.crt b/test-resources/certificate.crt
new file mode 100644
index 00000000..ee544493
--- /dev/null
+++ b/test-resources/certificate.crt
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF0zCCBLugAwIBAgIQByqysLNGGzf4RXfWDxaxzTANBgkqhkiG9w0BAQsFADA8
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRwwGgYDVQQDExNBbWF6b24g
+UlNBIDIwNDggTTAyMB4XDTIzMDIyMTAwMDAwMFoXDTIzMTAxNDIzNTk1OVowFjEU
+MBIGA1UEAxMLY2xvanVyZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC6JGRt221bAElnBPzSVOebsjPofEDQdLTfAr52LCQLCo/4x7cHsPTi9x4+
+W3Pl7Fq0yrgimBhJHT34z7UeFqHEMnjsGxt7dLY0XJ87iikd8pz+v9xqXW8rrGaT
+ykGx/85JFOGHJy+ZCparNYgUYN68IkaLe1QLb5w0GBcQa1U9JwpLqQVajrPDgD9Z
+YRBJqgaFzJuRVsXo28rxHHFdNlP6PF2scMSFrAZEaex0bLXDxw/bHChzjypPODuO
+ElsqxqI48Gsotqxe+iyP+Tu3B4GCHv2NKEFBYKiE+9UmNqQfXdVFvZFT+V2r4R9B
+SMv3hpDNjmDcgpCVxmCI1sUttfQvAgMBAAGjggL1MIIC8TAfBgNVHSMEGDAWgBTA
+MVLNWlDDgnx0cc7L6Zz5euuC4jAdBgNVHQ4EFgQUqkWGgRcK24T3gV3nNWwZ1EwQ
+MPUwJwYDVR0RBCAwHoILY2xvanVyZS5vcmeCD3d3dy5jbG9qdXJlLm9yZzAOBgNV
+HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDsGA1Ud
+HwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwucjJtMDIuYW1hem9udHJ1c3QuY29tL3Iy
+bTAyLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATB1BggrBgEFBQcBAQRpMGcwLQYI
+KwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnIybTAyLmFtYXpvbnRydXN0LmNvbTA2Bggr
+BgEFBQcwAoYqaHR0cDovL2NydC5yMm0wMi5hbWF6b250cnVzdC5jb20vcjJtMDIu
+Y2VyMAwGA1UdEwEB/wQCMAAwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB1AOg+
+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAABhnTETgYAAAQDAEYwRAIg
+IqyTlcuIQp6edqePX8mbZL42EgXfdTuFcBsoFdK9R5UCIEfKD8zISR0q08R2Zk6J
+xnHAwBNsMXbebXu0ez3CjeDDAHcAs3N3B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PAD
+Dnk2pZoAAAGGdMROQQAABAMASDBGAiEAhVldSvw96LP/Qb48ZnHC0LqtsV77t/zd
+7BCUNJY5bsACIQCENQ19xq5Yu7fWEB+qQQhjHlHD5yrocxqbdmMvdx9uggB2ALc+
++yTfnE26dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABhnTETg4AAAQDAEcwRQIh
+APsLYOmzOz3qoDCqBULup/twLLmLLu5pK7R/zP1lyPP4AiBZ7PQzi4K2pD8Rfcv1
+6Xm1oQwud8jmp1uQbnTCKHUPLjANBgkqhkiG9w0BAQsFAAOCAQEAdACtcuC2kFe0
+sQU1m6nnjXdXpds25Xa+Rfbls2vyTqrmatFhSleOhzbkTOnWv/tNunHikttp3+DR
+YOAbhJoUe4RVfuu1cQzL3kdc1q4MEmGgEl6V+jDO8657Ck1ld1ViGnqxKtncbV8b
+k7hUOurO2saQhlzgylKyFL02Re+kXgw4x/U1n20MvvzHU6QCpU6KcAUeQfub3orQ
+gEjmMxjOsnI38ZY8NX7guwhRiyFex3NOZ3avZxG6p8S5amXj8H6M8RBeQ07FVO3H
+wj/WczPsGo6D8RG0nU4MiGCerMiY1oF9navINFTZptWiy/gVhR85XwQrKu+Pt+AM
+47JAFeruig==
+-----END CERTIFICATE-----
diff --git a/test-resources/domain_sockets.bb b/test-resources/domain_sockets.bb
new file mode 100644
index 00000000..2d57eac5
--- /dev/null
+++ b/test-resources/domain_sockets.bb
@@ -0,0 +1,41 @@
+(import java.net.UnixDomainSocketAddress
+ java.net.StandardProtocolFamily
+ [java.nio.channels ServerSocketChannel SocketChannel])
+
+(require '[clojure.java.io :as io]
+ '[babashka.fs])
+
+(def sockaddr (UnixDomainSocketAddress/of
+ (-> (doto (fs/file (fs/temp-dir) "server.socket")
+ (.deleteOnExit))
+ str)))
+
+;; server
+(def server
+ (future
+ (let [ch (ServerSocketChannel/open StandardProtocolFamily/UNIX)]
+ (.bind ch sockaddr)
+ (.accept ch))))
+
+(Thread/sleep 100)
+
+ ;; client
+(let [ch (SocketChannel/open StandardProtocolFamily/UNIX)
+ ch (loop [retry 0]
+ (let [v (try (.connect ch sockaddr)
+ (catch Exception e e))]
+ (if (instance? Exception v)
+ (if (< retry 10)
+ (do (Thread/sleep 100)
+ (recur (inc retry)))
+ (throw v))
+ v)))]
+ #_(prn :ch ch)
+ #_(.close ch))
+
+@server
+
+(when-not (System/getProperty "babashka.version")
+ (shutdown-agents))
+
+:success
diff --git a/test-resources/lib_tests/babashka/run_all_libtests.clj b/test-resources/lib_tests/babashka/run_all_libtests.clj
index 092263f8..b9b70876 100644
--- a/test-resources/lib_tests/babashka/run_all_libtests.clj
+++ b/test-resources/lib_tests/babashka/run_all_libtests.clj
@@ -3,6 +3,7 @@
[babashka.classpath :as cp :refer [add-classpath]]
[babashka.core :refer [windows?]]
[babashka.fs :as fs]
+ [babashka.process :refer [sh]]
[clojure.edn :as edn]
[clojure.java.io :as io]
[clojure.spec.test.alpha :as st]
@@ -53,18 +54,30 @@
(swap! status (fn [status]
(merge-with + status (dissoc m :type))))))))))))
+(defn current-branch []
+ (or (System/getenv "APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH")
+ (System/getenv "APPVEYOR_REPO_BRANCH")
+ (System/getenv "CIRCLE_BRANCH")
+ (System/getenv "GITHUB_REF_NAME")
+ (System/getenv "CIRRUS_BRANCH")
+ (-> (sh "git" "rev-parse" "--abbrev-ref" "HEAD")
+ :out
+ str/trim)))
+
;; Standard test-runner for libtests
(let [lib-tests (edn/read-string (slurp (io/resource "bb-tested-libs.edn")))
test-nss (atom [])]
(doseq [[libname {tns :test-namespaces skip-windows :skip-windows
:keys [test-paths
- git-sha]}] lib-tests]
+ git-sha flaky]}] lib-tests]
(let [git-dir (format ".gitlibs/libs/%s/%s" libname git-sha)
git-dir (fs/file (fs/home) git-dir)]
(doseq [p test-paths]
(add-classpath (str (fs/file git-dir p)))))
(when-not (and skip-windows (windows?))
- (swap! test-nss into tns)))
+ (if (and flaky (#{"main" "master"} (current-branch)))
+ (println "Skipping" tns "for main branch because it's marked flaky")
+ (swap! test-nss into tns))))
(apply test-namespaces @test-nss))
;; Non-standard tests - These are tests with unusual setup around test-namespaces
@@ -80,13 +93,15 @@
(test-doric-cyclic-dep-problem))
;;;; babashka.process
-(when-not (windows?)
- ;; test built-in babashka.process
- (test-namespaces 'babashka.process-test)
+;; test built-in babashka.process
+(test-namespaces 'babashka.process-test)
+(when (= "native" (System/getenv "BABASHKA_TEST_ENV"))
;; test babashka.process from source
+ #_{:clj-kondo/ignore [:duplicate-require]}
(require '[babashka.process] :reload)
- (test-namespaces 'babashka.process-test))
+ (System/setProperty "babashka.process.test.reload" "true")
+ (test-namespaces 'babashka.process-test 'babashka.process-exec-test))
;;;; final exit code
diff --git a/test-resources/lib_tests/bb-tested-libs.edn b/test-resources/lib_tests/bb-tested-libs.edn
index d549dfa2..f7ba6189 100644
--- a/test-resources/lib_tests/bb-tested-libs.edn
+++ b/test-resources/lib_tests/bb-tested-libs.edn
@@ -46,8 +46,8 @@
com.github.seancorfield/honeysql {:git-sha "6e4e1f6928450788353c181f32474d930d6afe84", :git-url "https://github.com/seancorfield/honeysql", :test-namespaces (honey.sql-test honey.sql.helpers-test honey.sql.postgres-test), :branch "develop"}
honeysql/honeysql {:git-sha "1137dd12350afdc30ad4976c3718279581390b36", :git-url "https://github.com/seancorfield/honeysql", :test-namespaces (honeysql.format-test honeysql.core-test), :branch "v1"}
; skip tests on Windows because of the :compressed thing
- babashka/babashka.curl {:git-url "https://github.com/babashka/babashka.curl", :test-namespaces [babashka.curl-test], :skip-windows true, :manually-added true}
- http-kit/http-kit {:git-url "https://github.com/http-kit/http-kit", :test-namespaces [httpkit.client-test], :manually-added true}
+ babashka/babashka.curl {:git-url "https://github.com/babashka/babashka.curl", :test-namespaces [babashka.curl-test], :skip-windows true, :manually-added true :flaky true}
+ http-kit/http-kit {:git-url "https://github.com/http-kit/http-kit", :test-namespaces [httpkit.client-test], :manually-added true :flaky true}
org.clojure/core.match {:git-url "https://github.com/clojure/core.match", :test-namespaces [core-match.core-tests], :manually-added true}
hiccup/hiccup {:git-url "http://github.com/weavejester/hiccup", :test-namespaces [hiccup.core-test hiccup2.core-test], :manually-added true}
org.clojure/test.check {:git-url "https://github.com/clojure/test.check", :test-namespaces [test-check.smoke-test], :manually-added true}
@@ -57,15 +57,15 @@
crispin/crispin {:git-url "https://github.com/dunaj-project/crispin", :test-namespaces [crispin.core-test], :manually-added true}
clj-commons/multigrep {:git-url "https://github.com/clj-commons/multigrep", :test-namespaces [multigrep.core-test], :manually-added true}
org.clj-commons/digest {:git-url "https://github.com/clj-commons/clj-digest", :test-namespaces [clj-commons.digest-test], :manually-added true}
- hato/hato {:git-url "https://github.com/gnarroway/hato", :test-namespaces [hato.client-test], :manually-added true}
- java-http-clj/java-http-clj {:git-url "http://www.github.com/schmee/java-http-clj", :test-namespaces [java-http-clj.smoke-test], :manually-added true}
+ hato/hato {:git-url "https://github.com/gnarroway/hato", :test-namespaces [hato.client-test], :manually-added true :flaky true}
+ java-http-clj/java-http-clj {:git-url "http://www.github.com/schmee/java-http-clj", :test-namespaces [java-http-clj.smoke-test], :manually-added true :flaky true}
rewrite-clj/rewrite-clj {:git-url "https://github.com/clj-commons/rewrite-clj", :test-namespaces [rewrite-clj.parser-test rewrite-clj.node-test rewrite-clj.zip-test rewrite-clj.paredit-test rewrite-clj.zip.subedit-test rewrite-clj.node.coercer-test], :manually-added true}
;; TODO: env tests don't work because envoy lib isn't compatible with bb
;; TODO: failing tests in the following namespaces: vault.client.mock-test, vault.secrets.kvv1-test vault.secrets.kvv2-test
amperity/vault-clj {:git-url "https://github.com/amperity/vault-clj", :test-namespaces [vault.lease-test vault.client.http-test], :manually-added true}
orchestra/orchestra {:git-url "https://github.com/jeaye/orchestra", :test-namespaces (orchestra.make-fns orchestra.many-fns orchestra.expound-test orchestra.core-test orchestra.reload-test), :test-directories ("test/cljc" "test/clj"), :git-sha "81e5181f7b42e5e2763a2b37db17954f3be0314e"}
;; BB-TEST-PATCH: Deleted tasks.clj
- org.clj-commons/clj-http-lite {:git-url "https://github.com/clj-commons/clj-http-lite", :test-namespaces (clj-http.lite.test-runner clj-http.lite.client-test), :test-directories ("bb"), :git-sha "6b53000df55ac05c4ff8e5047a5323fc08a52e8b"}
+ org.clj-commons/clj-http-lite {:git-url "https://github.com/clj-commons/clj-http-lite", :test-namespaces (clj-http.lite.test-runner clj-http.lite.client-test), :test-directories ("bb"), :git-sha "6b53000df55ac05c4ff8e5047a5323fc08a52e8b" :flaky true}
cprop/cprop {:git-url "https://github.com/tolitius/cprop", :test-namespaces [cprop.smoke-test], :manually-added true}
org.clojure/data.zip {:git-url "https://github.com/clojure/data.zip", :test-namespaces [clojure.data.zip-test], :manually-added true}
borkdude/deps {:git-url "https://github.com/borkdude/deps.clj", :test-namespaces [borkdude.deps.smoke-test], :manually-added true}
@@ -94,7 +94,8 @@
progrock/progrock {:git-url "https://github.com/weavejester/progrock", :test-namespaces (progrock.core-test), :git-sha "9c277a3244c52bfde19c21add327d6e20b94fdf5"}
;; Don't run portal.jvm-test as it depends on headless chrome
djblue/portal {:git-url "https://github.com/djblue/portal", :test-namespaces (portal.test-runner portal.runtime.cson-test portal.runtime.fs-test portal.e2e portal.bench), :git-sha "64e4624bcf3bee2dd47e3d8e47982c709738eb11"}
- integrant/integrant {:git-url "https://github.com/weavejester/integrant", :test-namespaces (integrant.test.foo integrant.test.quz integrant.test.bar integrant.test.baz integrant.core-test), :git-sha "32a46f5dca8a6b563a6dddf88bec887be3201b08"}
+ integrant/integrant {:git-url "https://github.com/weavejester/integrant", :test-namespaces (integrant.test.foo integrant.test.quz integrant.test.bar integrant.test.baz integrant.core-test), :git-sha "a9fd7c02bd7201f36344b47142badc3c3ef22f88"
+ :test-paths ["test"]}
com.wsscode/cljc-misc {:git-url "https://github.com/wilkerlucio/cljc-misc", :test-namespaces (com.wsscode.misc.uuid-test com.wsscode.misc.macros-test com.wsscode.misc.math-test com.wsscode.misc.coll-test com.wsscode.misc.refs-test), :git-sha "dc8e31a200f9cacf86af10b63e40fcb448c259f4"}
edn-query-language/eql {:git-url "https://github.com/edn-query-language/eql", :test-namespaces (edn-query-language.core-test), :git-sha "0d4f9745d98c3d20b81bb4bdce3e8e15db7fd094"}
meta-merge/meta-merge {:git-url "https://github.com/weavejester/meta-merge", :test-namespaces (meta-merge.core-test), :git-sha "c968c38baccd4219fe0ba592d89af37ea8e426bf"}
@@ -182,4 +183,12 @@
org.clojure/tools.namespace {:git-sha "daf82a10e70182aea4c0716a48f3922163441b32",
:git-url "https://github.com/clojure/tools.namespace",
:test-namespaces [clojure.tools.namespace.test-helpers clojure.tools.namespace.dependency-test clojure.tools.namespace.find-test clojure.tools.namespace.move-test clojure.tools.namespace.parse-test],
- :test-paths ["src/test/clojure"]}}
+ :test-paths ["src/test/clojure"]}
+ net.cgrand/xforms {:git-url "https://github.com/cgrand/xforms",
+ :git-sha "550dbc150a79c6ecc148d8a7e260e10bc36321c6",
+ :test-namespaces [net.cgrand.xforms-test],
+ :test-paths ["test"]}
+ prismatic/plumbing {:git-url "https://github.com/plumatic/plumbing",
+ :git-sha "424bc704f2db422de34269c139a5494314b3a43b",
+ :test-namespaces [plumbing.core-test],
+ :test-paths ["test"]}}
diff --git a/test-resources/lib_tests/hato/client_test.clj b/test-resources/lib_tests/hato/client_test.clj
index d17d7b55..7c663710 100644
--- a/test-resources/lib_tests/hato/client_test.clj
+++ b/test-resources/lib_tests/hato/client_test.clj
@@ -331,7 +331,7 @@
(deftest ^:integration test-http2
(testing "can make an http2 request"
- (let [r (get "https://nghttp2.org/httpbin/get" {:as :json})]
+ (let [r (get "https://httpbin.org/get" {:as :json})]
(is (= :http-2 (:version r))))))
(deftest custom-middleware
diff --git a/test-resources/lib_tests/integrant/core_test.cljc b/test-resources/lib_tests/integrant/core_test.cljc
deleted file mode 100644
index ceeb60f7..00000000
--- a/test-resources/lib_tests/integrant/core_test.cljc
+++ /dev/null
@@ -1,549 +0,0 @@
-(ns integrant.core-test
- (:require [clojure.spec.alpha :as s]
- #?(:clj [clojure.test :refer :all]
- :cljs [cljs.test :refer-macros [are deftest is testing]])
- [integrant.core :as ig]
- [weavejester.dependency :as dep]))
-
-(def log (atom []))
-
-(defmethod ig/prep-key ::p [_ v]
- (merge {:a (ig/ref ::a)} v))
-
-(defmethod ig/init-key :default [k v]
- (swap! log conj [:init k v])
- [v])
-
-(defmethod ig/init-key ::x [k v]
- (swap! log conj [:init k v])
- :x)
-
-(defmethod ig/init-key ::error-init [_ _]
- (throw (ex-info "Testing" {:reason ::test})))
-
-(defmethod ig/init-key ::k [_ v] v)
-
-(defmethod ig/init-key ::n [_ v] (inc v))
-(defmethod ig/pre-init-spec ::n [_] nat-int?)
-
-(defmethod ig/init-key ::r [_ v] {:v v})
-(defmethod ig/resolve-key ::r [_ {:keys [v]}] v)
-(defmethod ig/resume-key ::r [k v _ _] (ig/init-key k v))
-
-(defmethod ig/halt-key! :default [k v]
- (swap! log conj [:halt k v]))
-
-(defmethod ig/halt-key! ::error-halt [_ _]
- (throw (ex-info "Testing" {:reason ::test})))
-
-(defmethod ig/resume-key :default [k cfg cfg' sys]
- (swap! log conj [:resume k cfg cfg' sys])
- [cfg])
-
-(defmethod ig/resume-key ::x [k cfg cfg' sys]
- (swap! log conj [:resume k cfg cfg' sys])
- :rx)
-
-(defmethod ig/suspend-key! :default [k v]
- (swap! log conj [:suspend k v]))
-
-(derive ::p ::pp)
-(derive ::pp ::ppp)
-
-(derive ::ap ::a)
-(derive ::ap ::p)
-
-(deftest ref-test
- (is (ig/ref? (ig/ref ::foo)))
- (is (ig/ref? (ig/ref [::foo ::bar])))
- (is (ig/reflike? (ig/ref ::foo)))
- (is (ig/reflike? (ig/ref [::foo ::bar]))))
-
-(deftest refset-test
- (is (ig/refset? (ig/refset ::foo)))
- (is (ig/refset? (ig/refset [::foo ::bar])))
- (is (ig/reflike? (ig/refset ::foo)))
- (is (ig/reflike? (ig/refset [::foo ::bar]))))
-
-(deftest composite-keyword-test
- (let [k (ig/composite-keyword [::a ::b])]
- (is (isa? k ::a))
- (is (isa? k ::b))
- (is (identical? k (ig/composite-keyword [::a ::b])))
- (is (not= k (ig/composite-keyword [::a ::c])))))
-
-(deftest valid-config-key-test
- (is (ig/valid-config-key? ::a))
- (is (not (ig/valid-config-key? :a))))
-
-(deftest expand-test
- (is (= (ig/expand {::a (ig/ref ::b), ::b 1})
- {::a 1, ::b 1}))
- (is (= (ig/expand {::a (ig/ref ::b), ::b (ig/ref ::c), ::c 2})
- {::a 2, ::b 2, ::c 2}))
- (is (= (ig/expand {::a (ig/ref ::pp), ::p 1})
- {::a 1, ::p 1}))
- (is (= (ig/expand {::a (ig/refset ::ppp), ::p 1, ::pp 2})
- {::a #{1 2}, ::p 1, ::pp 2}))
- (is (= (ig/expand {::a (ig/refset ::ppp)})
- {::a #{}})))
-
-#?(:clj
- (deftest read-string-test
- (is (= (ig/read-string "{:foo/a #ig/ref :foo/b, :foo/b 1}")
- {:foo/a (ig/ref :foo/b), :foo/b 1}))
- (is (= (ig/read-string "{:foo/a #ig/refset :foo/b, :foo/b 1}")
- {:foo/a (ig/refset :foo/b), :foo/b 1}))
- (is (= (ig/read-string {:readers {'test/var find-var}}
- "{:foo/a #test/var clojure.core/+}")
- {:foo/a #'+}))))
-
-;; BB-TEST-PATCH: No *loaded-libs* in bb
-#?(:bb :TODO :clj
- (defn- remove-lib [lib]
- (remove-ns lib)
- (dosync (alter @#'clojure.core/*loaded-libs* disj lib))))
-
-(derive :integrant.test-child/foo :integrant.test/foo)
-
-;; BB-TEST-PATCH: No *loaded-libs* in bb
-#?(:bb :TODO
- :clj
- (deftest load-namespaces-test
- (testing "all namespaces"
- (remove-lib 'integrant.test.foo)
- (remove-lib 'integrant.test.bar)
- (remove-lib 'integrant.test.baz)
- (remove-lib 'integrant.test.quz)
- (is (= (set (ig/load-namespaces {:integrant.test/foo 1
- :integrant.test.bar/wuz 2
- [:integrant.test/baz :integrant.test/x] 3
- [:integrant.test/y :integrant.test/quz] 4}))
- '#{integrant.test.foo
- integrant.test.bar
- integrant.test.baz
- integrant.test.quz}))
- (is (some? (find-ns 'integrant.test.foo)))
- (is (some? (find-ns 'integrant.test.bar)))
- (is (some? (find-ns 'integrant.test.baz)))
- (is (some? (find-ns 'integrant.test.quz)))
- (is (= (some-> 'integrant.test.foo/message find-var var-get) "foo"))
- (is (= (some-> 'integrant.test.bar/message find-var var-get) "bar"))
- (is (= (some-> 'integrant.test.baz/message find-var var-get) "baz"))
- (is (= (some-> 'integrant.test.quz/message find-var var-get) "quz")))
-
- (testing "some namespaces"
- (remove-lib 'integrant.test.foo)
- (remove-lib 'integrant.test.bar)
- (remove-lib 'integrant.test.baz)
- (remove-lib 'integrant.test.quz)
- (is (= (set (ig/load-namespaces
- {:integrant.test/foo 1
- :integrant.test/bar (ig/ref :integrant.test/foo)
- :integrant.test/baz 3}
- [:integrant.test/bar]))
- '#{integrant.test.foo
- integrant.test.bar}))
- (is (some? (find-ns 'integrant.test.foo)))
- (is (some? (find-ns 'integrant.test.bar)))
- (is (nil? (find-ns 'integrant.test.baz))))
-
- (testing "load namespaces of ancestors"
- (remove-lib 'integrant.test.foo)
- (is (= (set (ig/load-namespaces
- {:integrant.test-child/foo 1}))
- '#{integrant.test.foo}))
- (is (some? (find-ns 'integrant.test.foo))))))
-
-
-(deftest dependency-graph-test
- (let [m {::a (ig/ref ::p), ::b (ig/refset ::ppp) ::p 1, ::pp 2}]
- (testing "graph with refsets"
- (let [g (ig/dependency-graph m)]
- (is (dep/depends? g ::a ::p))
- (is (dep/depends? g ::b ::p))
- (is (dep/depends? g ::b ::pp))))
-
- (testing "graph without refsets"
- (let [g (ig/dependency-graph m {:include-refsets? false})]
- (is (dep/depends? g ::a ::p))
- (is (not (dep/depends? g ::b ::p)))
- (is (not (dep/depends? g ::b ::pp)))))))
-
-(deftest key-comparator-test
- (let [graph (ig/dependency-graph {::a (ig/ref ::ppp) ::p 1, ::b 2})]
- (is (= (sort (ig/key-comparator graph) [::b ::a ::p])
- [::p ::a ::b]))))
-
-(deftest derived-from?-test
- (are [a b] (ig/derived-from? a b)
- ::p ::p
- ::p ::pp
- ::p ::ppp
- ::ap [::a ::p]
- ::ap [::a ::pp]
- [::a ::p] [::a ::pp]
- [::a ::b ::p] [::a ::ppp]))
-
-(deftest find-derived-1-test
- (testing "missing key"
- (is (nil? (ig/find-derived-1 {} ::p))))
-
- (testing "derived key"
- (is (= (ig/find-derived-1 {::a "x" ::p "y"} ::pp)
- [::p "y"])))
-
- (testing "ambiguous key"
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- (re-pattern (str "Ambiguous key: " ::pp "\\. "
- "Found multiple candidates: " ::p ", " ::pp))
- (ig/find-derived-1 {::a "x" ::p "y", ::pp "z"} ::pp))))
-
- (testing "composite key"
- (is (= (ig/find-derived-1 {::a "x" [::b ::x] "y"} ::x)
- [[::b ::x] "y"]))))
-
-(deftest find-derived-test
- (testing "missing key"
- (is (nil? (ig/find-derived {} ::p))))
-
- (testing "derived key"
- (is (= (ig/find-derived {::a "x" ::p "y" ::pp "z"} ::pp)
- [[::p "y"] [::pp "z"]])))
-
- (testing "ambiguous key"
- (is (= (ig/find-derived {::a "x" ::p "y" ::pp "z"} ::ppp)
- [[::p "y"] [::pp "z"]])))
-
- (testing "composite key"
- (is (= (ig/find-derived {::a "x" [::b ::x] "y", [::b ::y] "z"} ::b)
- [[[::b ::x] "y"] [[::b ::y] "z"]]))))
-
-(deftest prep-test
- (testing "default"
- (is (= (ig/prep {::q {:b 2}, ::a 1})
- {::q {:b 2}, ::a 1})))
-
- (testing "custom prep-key"
- (is (= (ig/prep {::p {:b 2}, ::a 1})
- {::p {:a (ig/ref ::a), :b 2}, ::a 1})))
-
- (testing "prep then init"
- (is (= (ig/init (ig/prep {::p {:b 2}, ::a 1}))
- {::p [{:a [1], :b 2}], ::a [1]}))))
-
-(deftest init-test
- (testing "without keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), ::b 1})]
- (is (= m {::a [[1]], ::b [1]}))
- (is (= @log [[:init ::b 1]
- [:init ::a [1]]]))))
-
- (testing "with keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), ::b 1, ::c 2} [::a])]
- (is (= m {::a [[1]], ::b [1]}))
- (is (= @log [[:init ::b 1]
- [:init ::a [1]]]))))
-
- (testing "with inherited keys"
- (reset! log [])
- (let [m (ig/init {::p (ig/ref ::a), ::a 1} [::pp])]
- (is (= m {::p [[1]], ::a [1]}))
- (is (= @log [[:init ::a 1]
- [:init ::p [1]]]))))
-
- (testing "with composite keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), [::x ::b] 1})]
- (is (= m {::a [:x], [::x ::b] :x}))
- (is (= @log [[:init [::x ::b] 1]
- [:init ::a :x]]))))
-
- (testing "with composite refs"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref [::b ::c]), [::b ::c ::e] 1, [::b ::d] 2})]
- (is (= m {::a [[1]], [::b ::c ::e] [1], [::b ::d] [2]}))
- (is (or (= @log [[:init [::b ::c ::e] 1]
- [:init ::a [1]]
- [:init [::b ::d] 2]])
- (= @log [[:init [::b ::d] 2]
- [:init [::b ::c ::e] 1]
- [:init ::a [1]]])))))
-
- (testing "with failing composite refs"
- (reset! log [])
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- #"^Invalid composite key: \[:integrant.core-test/a :b\]. Every keyword must be namespaced.$"
- (ig/init {[::a :b] :anything}))))
-
- (testing "with custom resolve-key"
- (let [m (ig/init {::a (ig/ref ::r), ::r 1})]
- (is (= m {::a [1], ::r {:v 1}}))))
-
- (testing "with refsets"
- (reset! log [])
- (let [m (ig/init {::a (ig/refset ::ppp), ::p 1, ::pp 2})]
- (is (= m {::a [#{[1] [2]}], ::p [1], ::pp [2]}))
- (is (= @log [[:init ::p 1]
- [:init ::pp 2]
- [:init ::a #{[1] [2]}]]))))
-
- (testing "with refsets and keys"
- (reset! log [])
- (let [m {::a (ig/refset ::ppp), ::p 1, ::pp 2}]
- (is (= (ig/init m [::a]) {::a [#{}]}))
- (is (= (ig/init m [::a ::p]) {::a [#{[1]}] ::p [1]}))
- (is (= (ig/init m [::a ::pp]) {::a [#{[1] [2]}] ::p [1] ::pp [2]}))))
-
- (testing "large config"
- (is (= (ig/init {:a/a1 {} :a/a2 {:_ (ig/ref :a/a1)}
- :a/a3 {} :a/a4 {} :a/a5 {}
- :a/a6 {} :a/a7 {} :a/a8 {}
- :a/a9 {} :a/a10 {}})
- {:a/a1 [{}] :a/a2 [{:_ [{}]}]
- :a/a3 [{}] :a/a4 [{}] :a/a5 [{}]
- :a/a6 [{}] :a/a7 [{}] :a/a8 [{}]
- :a/a9 [{}] :a/a10 [{}]})))
-
- (testing "with passing specs"
- (let [m (ig/init {::n (ig/ref ::k), ::k 1})]
- (is (= m {::n 2, ::k 1}))))
-
- (testing "with failing specs"
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- (re-pattern (str "Spec failed on key " ::n " when building system"))
- (ig/init {::n (ig/ref ::k), ::k 1.1}))))
-
- (testing "with failing composite specs"
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- (re-pattern (str "Spec failed on key \\[" ::n " " ::nnn "\\] when building system"))
- (ig/init {[::n ::nnn] 1.1})))))
-
-(deftest halt-test
- (testing "without keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), ::b 1})]
- (ig/halt! m)
- (is (= @log [[:init ::b 1]
- [:init ::a [1]]
- [:halt ::a [[1]]]
- [:halt ::b [1]]]))))
-
- (testing "with keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), ::b (ig/ref ::c), ::c 1})]
- (ig/halt! m [::a])
- (is (= @log [[:init ::c 1]
- [:init ::b [1]]
- [:init ::a [[1]]]
- [:halt ::a [[[1]]]]]))
- (reset! log [])
- (ig/halt! m [::c])
- (is (= @log [[:halt ::a [[[1]]]]
- [:halt ::b [[1]]]
- [:halt ::c [1]]]))))
-
- (testing "with partial system"
- (reset! log [])
- (let [m (ig/init {::a 1, ::b (ig/ref ::a)} [::a])]
- (ig/halt! m)
- (is (= @log [[:init ::a 1]
- [:halt ::a [1]]]))))
-
- (testing "with inherited keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::p), ::p 1} [::a])]
- (ig/halt! m [::pp])
- (is (= @log [[:init ::p 1]
- [:init ::a [1]]
- [:halt ::a [[1]]]
- [:halt ::p [1]]]))))
-
- (testing "with composite keys"
- (reset! log [])
- (let [m (ig/init {::a (ig/ref ::b), [::x ::b] 1})]
- (ig/halt! m)
- (is (= @log [[:init [::x ::b] 1]
- [:init ::a :x]
- [:halt ::a [:x]]
- [:halt [::x ::b] :x]])))))
-
-(deftest suspend-resume-test
- (testing "same configuration"
- (reset! log [])
- (let [c {::a (ig/ref ::b), ::b 1}
- m (ig/init c)
- _ (ig/suspend! m)
- m' (ig/resume c m)]
- (is (= @log [[:init ::b 1]
- [:init ::a [1]]
- [:suspend ::a [[1]]]
- [:suspend ::b [1]]
- [:resume ::b 1 1 [1]]
- [:resume ::a [1] [1] [[1]]]]))))
-
- (testing "missing keys"
- (reset! log [])
- (let [c {::a (ig/ref ::b), ::b 1}
- m (ig/init c)
- _ (ig/suspend! m)
- m' (ig/resume (dissoc c ::a) m)]
- (is (= @log [[:init ::b 1]
- [:init ::a [1]]
- [:suspend ::a [[1]]]
- [:suspend ::b [1]]
- [:halt ::a [[1]]]
- [:resume ::b 1 1 [1]]]))))
-
- (testing "missing refs"
- (reset! log [])
- (let [c {::a {:b (ig/ref ::b)}, ::b 1}
- m (ig/init c)
- _ (ig/suspend! m)
- m' (ig/resume {::a []} m)]
- (is (= @log [[:init ::b 1]
- [:init ::a {:b [1]}]
- [:suspend ::a [{:b [1]}]]
- [:suspend ::b [1]]
- [:halt ::b [1]]
- [:resume ::a [] {:b [1]} [{:b [1]}]]]))))
-
- (testing "with custom resolve-key"
- (let [c {::a (ig/ref ::r), ::r 1}
- m (ig/init c)
- _ (ig/suspend! m)
- m' (ig/resume c m)]
- (is (= m m'))))
-
- (testing "composite keys"
- (reset! log [])
- (let [c {::a (ig/ref ::x), [::b ::x] 1}
- m (ig/init c)
- _ (ig/suspend! m)
- m' (ig/resume c m)]
- (is (= @log [[:init [::b ::x] 1]
- [:init ::a :x]
- [:suspend ::a [:x]]
- [:suspend [::b ::x] :x]
- [:resume [::b ::x] 1 1 :x]
- [:resume ::a :rx :x [:x]]]))))
-
- (testing "resume key with dependencies"
- (reset! log [])
- (let [c {::a {:b (ig/ref ::b)}, ::b 1}
- m (ig/init c [::a])
- _ (ig/suspend! m)
- m' (ig/resume c m [::a])]
- (is (= @log
- [[:init ::b 1]
- [:init ::a {:b [1]}]
- [:suspend ::a [{:b [1]}]]
- [:suspend ::b [1]]
- [:resume ::b 1 1 [1]]
- [:resume ::a {:b [1]} {:b [1]} [{:b [1]}]]])))))
-
-(deftest invalid-configs-test
- (testing "ambiguous refs"
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- (re-pattern (str "Ambiguous key: " ::ppp "\\. "
- "Found multiple candidates: "
- "(" ::p ", " ::pp "|" ::pp ", " ::p ")"))
- (ig/init {::a (ig/ref ::ppp), ::p 1, ::pp 2}))))
-
- (testing "missing refs"
- (is (thrown-with-msg?
- #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
- (re-pattern (str "Missing definitions for refs: " ::b))
- (ig/init {::a (ig/ref ::b)}))))
-
- (testing "missing refs with explicit keys"
- (is (= (ig/init {::a (ig/ref ::ppp), ::p 1, ::pp 2} [::p ::pp])
- {::p [1], ::pp [2]})))
-
- (testing "missing refs with explicit keys"
- (is (= (ig/init {::a 1, ::b (ig/ref ::c)} [::a])
- {::a [1]}))))
-
-(defn build-log [config]
- (let [log (atom [])]
- [(ig/build config (keys config) (fn [k v] (last (swap! log conj [:build k v]))))
- @log]))
-
-(deftest build-test
- (is (= [{::a [:build ::a [:build ::b 1]]
- ::b [:build ::b 1]}
- [[:build ::b 1]
- [:build ::a [:build ::b 1]]]]
- (build-log {::a (ig/ref ::b)
- ::b 1}))))
-
-(defn test-log [f m]
- (let [log (atom [])]
- [(f m (keys m) (fn [k v] (last (swap! log conj [:test k v]))))
- @log]))
-
-(deftest run-test* ;; BB-TEST-PATCH: renamed due to conflict with clojure.test
- (let [config {::a (ig/ref ::b), ::b 1}
- [system _] (build-log config)]
- (is (= [nil
- [[:test ::b [:build ::b 1]]
- [:test ::a [:build ::a [:build ::b 1]]]]]
- (test-log ig/run! system)))
- (is (= [nil
- [[:test ::a [:build ::a [:build ::b 1]]]
- [:test ::b [:build ::b 1]]]]
- (test-log ig/reverse-run! system)))))
-
-(deftest fold-test
- (let [config {::a (ig/ref ::ppp), ::b (ig/ref ::pp), ::p 1, ::c 2}
- system (ig/init config)]
- (is (= (ig/fold system #(conj %1 [%2 %3]) [])
- [[::p [1]] [::a [[1]]] [::b [[1]]] [::c [2]]]))))
-
-(deftest wrapped-exception-test
- (testing "exception when building"
- (let [ex (try (ig/init {::a 1, ::error-init (ig/ref ::a)}) nil
- (catch #?(:clj Throwable :cljs :default) t t))]
- (is (some? ex))
- (is (= (#?(:clj .getMessage :cljs ex-message) ex)
- (str "Error on key " ::error-init " when building system")))
- (is (= (ex-data ex)
- {:reason ::ig/build-threw-exception
- :system {::a [1]}
- :function ig/init-key
- :key ::error-init
- :value [1]}))
- (let [cause (#?(:clj .getCause :cljs ex-cause) ex)]
- (is (some? cause))
- (is (= (#?(:clj .getMessage :cljs ex-message) cause) "Testing"))
- (is (= (ex-data cause) {:reason ::test})))))
-
- (testing "exception when running"
- (let [system (ig/init {::a 1
- ::error-halt (ig/ref ::a)
- ::b (ig/ref ::error-halt)
- ::c (ig/ref ::b)})
- ex (try (ig/halt! system)
- (catch #?(:clj Throwable :cljs :default) t t))]
- (is (some? ex))
- (is (= (#?(:clj .getMessage :cljs ex-message) ex)
- (str "Error on key " ::error-halt " when running system")))
- (is (= (ex-data ex)
- {:reason ::ig/run-threw-exception
- :system {::a [1], ::error-halt [[1]], ::b [[[1]]], ::c [[[[1]]]]}
- :completed-keys '(::c ::b)
- :remaining-keys '(::a)
- :function ig/halt-key!
- :key ::error-halt
- :value [[1]]}))
- (let [cause (#?(:clj .getCause :cljs ex-cause) ex)]
- (is (some? cause))
- (is (= (#?(:clj .getMessage :cljs ex-message) cause) "Testing"))
- (is (= (ex-data cause) {:reason ::test}))))))
diff --git a/test-resources/lib_tests/integrant/test/bar.clj b/test-resources/lib_tests/integrant/test/bar.clj
deleted file mode 100644
index e24dec6a..00000000
--- a/test-resources/lib_tests/integrant/test/bar.clj
+++ /dev/null
@@ -1,3 +0,0 @@
-(ns integrant.test.bar)
-
-(def message "bar")
diff --git a/test-resources/lib_tests/integrant/test/baz.clj b/test-resources/lib_tests/integrant/test/baz.clj
deleted file mode 100644
index bf565ab7..00000000
--- a/test-resources/lib_tests/integrant/test/baz.clj
+++ /dev/null
@@ -1,3 +0,0 @@
-(ns integrant.test.baz)
-
-(def message "baz")
diff --git a/test-resources/lib_tests/integrant/test/foo.clj b/test-resources/lib_tests/integrant/test/foo.clj
deleted file mode 100644
index 3d9ab7d5..00000000
--- a/test-resources/lib_tests/integrant/test/foo.clj
+++ /dev/null
@@ -1,3 +0,0 @@
-(ns integrant.test.foo)
-
-(def message "foo")
diff --git a/test-resources/lib_tests/integrant/test/quz.clj b/test-resources/lib_tests/integrant/test/quz.clj
deleted file mode 100644
index 7ebd2a8b..00000000
--- a/test-resources/lib_tests/integrant/test/quz.clj
+++ /dev/null
@@ -1,3 +0,0 @@
-(ns integrant.test.quz)
-
-(def message "quz")
diff --git a/test-resources/lib_tests/integrant/test_runner.cljs b/test-resources/lib_tests/integrant/test_runner.cljs
deleted file mode 100644
index 8e014182..00000000
--- a/test-resources/lib_tests/integrant/test_runner.cljs
+++ /dev/null
@@ -1,5 +0,0 @@
-(ns integrant.test-runner
- (:require [doo.runner :refer-macros [doo-tests]]
- [integrant.core-test]))
-
-(doo-tests 'integrant.core-test)
diff --git a/test-resources/lib_tests/rewrite_clj/node/coercer_test.cljc b/test-resources/lib_tests/rewrite_clj/node/coercer_test.cljc
index f0e858e3..fbb9ff8d 100644
--- a/test-resources/lib_tests/rewrite_clj/node/coercer_test.cljc
+++ b/test-resources/lib_tests/rewrite_clj/node/coercer_test.cljc
@@ -1,67 +1,77 @@
(ns rewrite-clj.node.coercer-test
(:require [clojure.test :refer [deftest testing is are]]
[rewrite-clj.node :as node]
+ [rewrite-clj.node.protocols :as protocols]
+ [rewrite-clj.node.regex :as regex]
[rewrite-clj.parser :as p]))
(deftest t-sexpr->node->sexpr-roundtrip
(testing "simple cases roundtrip"
- (are [?sexpr expected-tag ]
+ (are [?sexpr expected-tag expected-type]
(let [n (node/coerce ?sexpr)]
(is (node/node? n))
(is (= ?sexpr (node/sexpr n)))
(is (string? (node/string n)))
(is (= expected-tag (node/tag n)) "tag")
+ #_(is (= expected-type (protocols/node-type n)) "node-type")
(is (not (meta n)))
- (is (= (type ?sexpr) (type (node/sexpr n)))))
+ (if (seq? ?sexpr)
+ (is (seq? (node/sexpr n)))
+ (is (= (type (node/sexpr n)) (type ?sexpr) ))))
;; numbers
;; note that we do have an integer-node, but rewrite-clj never parses to it
;; so we never coerce to it either
- 3 :token ;;:token
- 3N :token ;;:token
- 3.14 :token ;;:token
- 3.14M :token ;;:token
- 3e14 :token ;;:token
+ 3 :token :token
+ 3N :token :token
+ 3.14 :token :token
+ 3.14M :token :token
+ 3e14 :token :token
;; ratios are not valid in cljs
- #?@(:clj [3/4 :token ;;:token
- ]
- )
+ #?@(:clj [3/4 :token :token])
;; symbol/keyword/string/...
- 'symbol :token ;;:symbol
- 'namespace/symbol :token ;;:symbol
- :keyword :token ;;:keyword
- :1.5.1 :token ;;:keyword
- ::keyword :token ;;:keyword
- ::1.5.1 :token ;;:keyword
- :namespace/keyword :token ;;:keyword
+ 'symbol :token :symbol
+ 'namespace/symbol :token :symbol
+ :keyword :token :keyword
+ :1.5.1 :token :keyword
+ ::keyword :token :keyword
+ ::1.5.1 :token :keyword
+ :namespace/keyword :token :keyword
- "" :token ;;:string
- "hello, over there!" :token ;;:string
- "multi\nline" :multi-line ;;:string
- " " :token ;;:string
- "\n" :multi-line ;;:string
- "\n\n" :multi-line ;;:string
- "," :token ;;:string
+ "" :token :string
+ "hello, over there!" :token :string
+ "multi\nline" :token :string
+ " " :token :string
+ "\n" :token :string
+ "\n\n" :token :string
+ "," :token :string
+ "inner\"quote" :token :string
+ "\\s+" :token :string
;; seqs
- [] :vector ;;:seq
- [1 2 3] :vector ;;:seq
- () :list ;;:seq
- '() :list ;;:seq
- (list 1 2 3) :list ;;:seq
- #{} :set ;;:seq
- #{1 2 3} :set ;;:seq
+ [] :vector :seq
+ [1 2 3] :vector :seq
+ () :list :seq
+ '() :list :seq
+ (list 1 2 3) :list :seq
+ #{} :set :seq
+ #{1 2 3} :set :seq
+ (cons 1 [2 3]) :list :seq
+ (lazy-seq [1 2 3]) :list :seq
;; date
- #inst "2014-11-26T00:05:23" :token ;; :token
- ))
- (testing "multi-line string newline variants are normalized"
+ #inst "2014-11-26T00:05:23" :token :token))
+ (testing "multi-line string newline variants are preserved"
(let [s "hey\nyou\rover\r\nthere"
n (node/coerce s)]
- (is (= "hey\nyou\nover\nthere" (node/sexpr n))))))
+ (is (= s (node/sexpr n)))))
+ (testing "coerce string roundtrip"
+ (is (= "\"hey \\\" man\"" (-> "hey \" man" node/coerce node/string))))
+ (testing "coerce string equals parsed string"
+ (is (= (p/parse-string "\"hello\"") (node/coerce "hello")))))
(deftest
t-quoted-list-reader-location-metadata-elided
@@ -81,7 +91,7 @@
(let [n (node/coerce ?sexpr)]
(is (node/node? n))
(is (= :map (node/tag n)))
- ;; (is (= :seq protocols/node-type n))
+ #_(is (= :seq (protocols/node-type n)))
(is (string? (node/string n)))
(is (= ?sexpr (node/sexpr n)))
;; we do not restore to original map (hash-map or array-map),
@@ -94,27 +104,16 @@
(array-map)
(array-map :d 4 :e 5)))
-(deftest t-namespaced-maps-coerce-to-maps
- (are [?sexpr]
- (let [n (node/coerce ?sexpr)]
- (is (node/node? n))
- (is (= :map (node/tag n)))
- ;; (is (= :seq (protocols/node-type n)))
- (is (string? (node/string n)))
- (is (= ?sexpr (node/sexpr n)))
- (is (map? (node/sexpr n))))
- #:prefix {:a 1 :b 2}
- #::{:c 3 :d 4}
- #::p{:e 5 :f 6}))
+
(deftest t-sexpr->node->sexpr-roundtrip-for-regex
(are [?in]
(let [n (node/coerce ?in)]
(is (node/node? n))
(is (= :regex (node/tag n)))
- ;; (is (= :regex (protocols/node-type n)))
+ #_(is (= :regex (protocols/node-type n)))
(is (string? (node/string n)))
- #_(is (= (list 're-pattern (regex/pattern-string-for-regex ?in))
+ (is (= (list 're-pattern (regex/pattern-string-for-regex ?in))
(node/sexpr n))))
#"abc"
#"a\nb\nc"
@@ -127,7 +126,7 @@
(let [n (node/coerce #'identity)]
(is (node/node? n))
(is (= :var (node/tag n)))
- #_(is (= :reader (protocols/node-type n)))
+ (is (= :reader (protocols/node-type n)))
(is (= '(var #?(:clj clojure.core/identity :cljs cljs.core/identity)) (node/sexpr n)))))
(deftest t-nil
@@ -153,31 +152,30 @@
(deftest t-nodes-coerce-to-themselves
(testing "parsed nodes"
;; lean on the parser to create node structures
- (are [?s ?tag #_?type]
+ (are [?s ?tag ?type]
(let [n (p/parse-string ?s)]
(is (= n (node/coerce n)))
(is (= ?tag (node/tag n)))
#_(is (= ?type (protocols/node-type n))))
- ";; comment" :comment ;;:comment
- "#! comment" :comment ;;:comment
- "#(+ 1 %)" :fn ;;:fn
- ":my-kw" :token ;;:keyword
- "^:m1 [1 2 3]" :meta ;;:meta
- "#:p1{:a 1 :b 2}" :namespaced-map ;;:namespaced-map
- "'a" :quote ;;:quote
- "#'var" :var ;;:reader
- "#=eval" :eval ;;:reader
- "@deref" :deref ;;:deref
- "#mymacro 44" :reader-macro ;;:reader-macro
- "#\"regex\"" :regex ;;:regex
- "[1 2 3]" :vector ;;:seq
- "42" :token ;;:token
- "sym" :token ;;:symbol
- "#_ 99" :uneval ;;:uneval
- " " :whitespace ;;:whitespace
- "," :comma ;;:comma
- "\n" :newline ;;:newline
- ))
+ ";; comment" :comment :comment
+ "#! comment" :comment :comment
+ "#(+ 1 %)" :fn :fn
+ ":my-kw" :token :keyword
+ "^:m1 [1 2 3]" :meta :meta
+ "#:p1{:a 1 :b 2}" :namespaced-map :namespaced-map
+ "'a" :quote :quote
+ "#'var" :var :reader
+ "#=eval" :eval :reader
+ "@deref" :deref :deref
+ "#mymacro 44" :reader-macro :reader-macro
+ "#\"regex\"" :regex :regex
+ "[1 2 3]" :vector :seq
+ "42" :token :token
+ "sym" :token :symbol
+ "#_ 99" :uneval :uneval
+ " " :whitespace :whitespace
+ "," :comma :comma
+ "\n" :newline :newline))
(testing "parsed forms nodes"
(let [n (p/parse-string-all "(def a 1)")]
(is (= n (node/coerce n)))
diff --git a/test-resources/lib_tests/selmer/core_test.clj b/test-resources/lib_tests/selmer/core_test.clj
index 0e200953..72b55012 100644
--- a/test-resources/lib_tests/selmer/core_test.clj
+++ b/test-resources/lib_tests/selmer/core_test.clj
@@ -8,7 +8,8 @@
[selmer.filters :as f]
[selmer.parser :as p :refer [render render-file render-template
parse parse-input known-variables
- << resolve-var-from-kw env-map]]
+ << resolve-var-from-kw env-map
+ resolve-arg]]
[selmer.tags :as tags]
[clojure.set :as set])
(:import (java.io StringReader ByteArrayInputStream)
@@ -1294,3 +1295,32 @@
(is (= "false" (let [y false] (<< "{{y}}")))
"<< picks up local values even if they are false"))
+
+(deftest resolve-arg-test
+ (is (= "John"
+ (resolve-arg "{{variable}}" {:variable "John"}))
+ "When arg is a variable, returns it substituted by its value.")
+ (is (= "Hello John!"
+ (resolve-arg "Hello {{variable}}!" {:variable "John"}))
+ "When arg contains a variable, return it with the variable substituted by its value.")
+ (is (= "JOHN"
+ (resolve-arg "{{variable|upper}}" {:variable "John"}))
+ "When arg is a filter, returns it where the filter was applied to its value.")
+ (is (= "Hello JOHN!"
+ (resolve-arg "Hello {{variable|upper}}!" {:variable "John"}))
+ "When arg contains a filter, returns it where the filter was applied to its value.")
+ (is (= "Mr John"
+ (resolve-arg "{% if variable = \"John\" %}Mr {{variable}}{% endif %}" {:variable "John"}))
+ "When arg is a tag, returns it where the tag was rendered to its value.")
+ (is (= "Hello Mr John!"
+ (resolve-arg "Hello {% if variable = \"John\" %}Mr {{variable}}{% endif %}!" {:variable "John"}))
+ "When arg contains a tag, returns it where the tag was rendered to its value.")
+ (is (= "Hello John!"
+ (resolve-arg "\"Hello John!\"" {}))
+ "When arg is a double quoted literal string, returns it without double quoting.")
+ (is (= "Hello John!"
+ (resolve-arg "Hello John!" {}))
+ "When arg is a literal string, returns it as is.")
+ (is (= "29.99"
+ (resolve-arg "29.99" {}))
+ "When arg is a literal number, returns it as is."))
diff --git a/test-resources/local-dep/deps.edn b/test-resources/local-dep/deps.edn
new file mode 100644
index 00000000..ccd9a316
--- /dev/null
+++ b/test-resources/local-dep/deps.edn
@@ -0,0 +1 @@
+{:paths ["src"]}
diff --git a/test-resources/local-dep/src/local_dep.clj b/test-resources/local-dep/src/local_dep.clj
new file mode 100644
index 00000000..c12396c0
--- /dev/null
+++ b/test-resources/local-dep/src/local_dep.clj
@@ -0,0 +1,3 @@
+(ns local-dep)
+
+(def local-dep-var :foo)
diff --git a/test-resources/script_with_overlapping_opts.clj b/test-resources/script_with_overlapping_opts.clj
new file mode 100644
index 00000000..5b71e3dc
--- /dev/null
+++ b/test-resources/script_with_overlapping_opts.clj
@@ -0,0 +1 @@
+(prn *command-line-args*)
diff --git a/test-resources/symlink-adjacent-bb b/test-resources/symlink-adjacent-bb
new file mode 120000
index 00000000..40b5d4bf
--- /dev/null
+++ b/test-resources/symlink-adjacent-bb
@@ -0,0 +1 @@
+adjacent_bb/medley.bb
\ No newline at end of file
diff --git a/test/babashka/async_test.clj b/test/babashka/async_test.clj
index 7fd1050c..770ac9aa 100644
--- a/test/babashka/async_test.clj
+++ b/test/babashka/async_test.clj
@@ -42,3 +42,11 @@
[(async/go
(async/ (list 'shell {:out out
- :err out
+ (test-utils/with-config {:tasks {'foo (list '-> (list 'shell {:out out
+ :err out
:continue '(fn [proc]
(contains? proc :exit))}
ls-cmd "foobar")
@@ -94,8 +94,8 @@
(is (pos? (bb "run" "--prn" "foo")))))
(testing "shell test with :error"
(test-utils/with-config
- {:tasks {'foo (list '-> (list 'shell {:out out
- :err out
+ {:tasks {'foo (list '-> (list 'shell {:out out
+ :err out
:error-fn '(constantly 1337)}
ls-cmd "foobar"))}}
(is (= 1337 (bb "run" "--prn" "foo"))))
@@ -118,23 +118,23 @@
(fs/delete out)
(testing "depends"
(test-utils/with-config {:tasks {'quux (list 'spit out "quux\n")
- 'baz (list 'spit out "baz\n" :append true)
- 'bar {:depends ['baz]
- :task (list 'spit out "bar\n" :append true)}
- 'foo {:depends ['quux 'bar 'baz]
- :task (list 'spit out "foo\n" :append true)}}}
+ 'baz (list 'spit out "baz\n" :append true)
+ 'bar {:depends ['baz]
+ :task (list 'spit out "bar\n" :append true)}
+ 'foo {:depends ['quux 'bar 'baz]
+ :task (list 'spit out "foo\n" :append true)}}}
(bb "foo")
(is (= "quux\nbaz\nbar\nfoo\n" (slurp out)))))
(fs/delete out)
;; This is why we don't support :when for now
#_(testing "depends with :when"
(test-utils/with-config {:tasks {'quux (list 'spit out "quux\n")
- 'baz (list 'spit out "baz\n" :append true)
- 'bar {:when false
- :depends ['baz]
- :task (list 'spit out "bar\n" :append true)}
- 'foo {:depends ['quux 'bar]
- :task (list 'spit out "foo\n" :append true)}}}
+ 'baz (list 'spit out "baz\n" :append true)
+ 'bar {:when false
+ :depends ['baz]
+ :task (list 'spit out "bar\n" :append true)}
+ 'foo {:depends ['quux 'bar]
+ :task (list 'spit out "foo\n" :append true)}}}
(bb "foo")
(is (= "quux\nbaz\nbar\nfoo\n" (slurp out))))))
(testing "fully qualified symbol execution"
@@ -143,34 +143,34 @@
(is (= :foo (bb "run" "--prn" "foo"))))
(test-utils/with-config {:paths ["test-resources/task_scripts"]
:tasks '{:requires ([tasks :as t])
- foo t/foo}}
+ foo t/foo}}
(is (= :foo (bb "run" "--prn" "foo"))))
(test-utils/with-config {:paths ["test-resources/task_scripts"]
:tasks '{foo {:requires ([tasks :as t])
- :task t/foo}}}
+ :task t/foo}}}
(is (= :foo (bb "run" "--prn" "foo")))))
(testing "extra-paths"
(test-utils/with-config {:paths ["test-resources/task_scripts"]
:tasks '{:requires ([tasks :as t])
- foo {:extra-paths ["test-resources/task_test_scripts"]
- :requires ([task-test :as tt])
- :task tt/task-test-fn}}}
+ foo {:extra-paths ["test-resources/task_test_scripts"]
+ :requires ([task-test :as tt])
+ :task tt/task-test-fn}}}
(is (= :task-test-fn (bb "run" "--prn" "foo")))))
(testing "extra-deps"
(test-utils/with-config {:tasks '{foo {:extra-deps {medley/medley {:mvn/version "1.3.0"}}
- :requires ([medley.core :as m])
- :task (m/index-by :id [{:id 1} {:id 2}])}}}
+ :requires ([medley.core :as m])
+ :task (m/index-by :id [{:id 1} {:id 2}])}}}
(is (= {1 {:id 1}, 2 {:id 2}} (bb "run" "--prn" "foo")))))
(testing "enter / leave"
- (test-utils/with-config '{:tasks {:init (do (def enter-ctx (atom []))
- (def leave-ctx (atom [])))
+ (test-utils/with-config '{:tasks {:init (do (def enter-ctx (atom []))
+ (def leave-ctx (atom [])))
:enter (swap! enter-ctx conj (:name (current-task)))
:leave (swap! leave-ctx conj (:name (current-task)))
- foo {:depends [bar]
- :task [@enter-ctx @leave-ctx]}
- bar {:depends [baz]}
- baz {:enter nil
- :leave nil}}}
+ foo {:depends [bar]
+ :task [@enter-ctx @leave-ctx]}
+ bar {:depends [baz]}
+ baz {:enter nil
+ :leave nil}}}
(is (= '[[bar foo] [bar]] (bb "run" "--prn" "foo")))))
(testing "run"
(test-utils/with-config '{:tasks {a (+ 1 2 3)
@@ -184,28 +184,28 @@
(testing "unresolved dependency"
(test-utils/with-config '{:tasks {a (+ 1 2 3)
b {:depends [x]
- :task (+ a 4 5 6)}}}
+ :task (+ a 4 5 6)}}}
(is (thrown-with-msg?
Exception #"No such task: x"
(bb "run" "b")))))
(testing "cyclic task"
(test-utils/with-config '{:tasks {b {:depends [b]
- :task (+ a 4 5 6)}}}
+ :task (+ a 4 5 6)}}}
(is (thrown-with-msg?
Exception #"Cyclic task: b"
(bb "run" "b"))))
(test-utils/with-config '{:tasks {c {:depends [b]}
b {:depends [c]
- :task (+ a 4 5 6)}}}
+ :task (+ a 4 5 6)}}}
(is (thrown-with-msg?
Exception #"Cyclic task: b"
(bb "run" "b")))))
(testing "friendly regex literal error handling"
(test-utils/with-config
- "{:tasks {something (clojure.string/split \"1-2\" #\"-\")}}"
- (is (thrown-with-msg?
- Exception #"Invalid regex literal"
- (bb "run" "something")))))
+ "{:tasks {something (clojure.string/split \"1-2\" #\"-\")}}"
+ (is (thrown-with-msg?
+ Exception #"Invalid regex literal"
+ (bb "run" "something")))))
(testing "doc"
(test-utils/with-config '{:tasks {b {:doc "Beautiful docstring"}}}
(let [s (test-utils/bb nil "doc" "b")]
@@ -216,21 +216,21 @@
(is (= "b" s)))))
(testing "parallel test"
(test-utils/with-config (edn/read-string (slurp "test-resources/coffee-tasks.edn"))
- (let [tree [:made-coffee [[:ground-beans [:measured-beans]] [:heated-water [:poured-water]] :filter :mug]]
- t0 (System/currentTimeMillis)
- s (bb "run" "--prn" "coffeep")
- t1 (System/currentTimeMillis)
+ (let [tree [:made-coffee [[:ground-beans [:measured-beans]] [:heated-water [:poured-water]] :filter :mug]]
+ t0 (System/currentTimeMillis)
+ s (bb "run" "--prn" "coffeep")
+ t1 (System/currentTimeMillis)
delta-sequential (- t1 t0)]
(is (= tree s))
(test-utils/with-config (edn/read-string (slurp "test-resources/coffee-tasks.edn"))
- (let [t0 (System/currentTimeMillis)
- s (bb "run" "--parallel" "--prn" "coffeep")
- t1 (System/currentTimeMillis)
+ (let [t0 (System/currentTimeMillis)
+ s (bb "run" "--parallel" "--prn" "coffeep")
+ t1 (System/currentTimeMillis)
delta-parallel (- t1 t0)]
(is (= tree s))
- (when (>= (doto (-> (Runtime/getRuntime) (.availableProcessors))
- (prn))
- 2)
+ (when (>= (doto (-> (Runtime/getRuntime) (.availableProcessors))
+ (prn))
+ 2)
(is (< delta-parallel delta-sequential)))))))
(testing "exception"
(test-utils/with-config '{:tasks {a (Thread/sleep 10000)
@@ -241,40 +241,40 @@
(bb "run" "--parallel" "c")))))
(testing "edge case"
(test-utils/with-config '{:tasks
- {a (run '-a {:parallel true})
- -a {:depends [a:a a:b c]
- :task (prn [a:a a:b c])}
+ {a (run '-a {:parallel true})
+ -a {:depends [a:a a:b c]
+ :task (prn [a:a a:b c])}
a:a {:depends [c]
- :task (+ 1 2 3)}
+ :task (+ 1 2 3)}
a:b {:depends [c]
- :task (do (Thread/sleep 10)
- (+ 1 2 3))}
- c (do (Thread/sleep 10) :c)}}
+ :task (do (Thread/sleep 10)
+ (+ 1 2 3))}
+ c (do (Thread/sleep 10) :c)}}
(is (= [6 6 :c] (bb "run" "--prn" "a"))))))
(testing "dynamic vars"
(test-utils/with-config '{:tasks
{:init (def ^:dynamic *foo* true)
- a (do
- (def ^:dynamic *bar* false)
- (binding [*foo* false
- *bar* true]
- [*foo* *bar*]))}}
+ a (do
+ (def ^:dynamic *bar* false)
+ (binding [*foo* false
+ *bar* true]
+ [*foo* *bar*]))}}
(is (= [false true] (bb "run" "--prn" "a")))))
(testing "stable namespace name"
(test-utils/with-config '{:tasks
- {:init (do (def ^:dynamic *jdk*)
- (def ^:dynamic *server*))
- server [*jdk* *server*]
- run-all (for [jdk [8 11 15]
+ {:init (do (def ^:dynamic *jdk*)
+ (def ^:dynamic *server*))
+ server [*jdk* *server*]
+ run-all (for [jdk [8 11 15]
server [:foo :bar]]
- (binding [*jdk* jdk
+ (binding [*jdk* jdk
*server* server]
(babashka.tasks/run 'server)))}}
(is (= '([8 :foo] [8 :bar] [11 :foo] [11 :bar] [15 :foo] [15 :bar])
(bb "run" "--prn" "run-all")))))
;; TODO: disabled because of " Volume in drive C has no label.\r\n Volume Serial Number is 1CB8-D4AA\r\n\r\n Directory of C:\\projects\\babashka\r\n\r\n" on Appveyor. See https://ci.appveyor.com/project/borkdude/babashka/builds/40003094.
(testing "shell test with :continue"
- (let [ls-cmd (if main/windows? "cmd /c dir" "ls")]
+ (let [ls-cmd (if main/windows? "cmd /c dir" "ls")]
(test-utils/with-config {:tasks {'foo (list 'do
(list 'shell {:continue true}
(str ls-cmd " foobar"))
@@ -303,6 +303,27 @@
(let [s (bb "run" "--prn" "a")]
(is (str/includes? s "paths")))))))
+(deftest tasks:clojure-test
+ (testing "tokenization when called from tasks"
+ (test-utils/with-config
+ (pr-str '{:tasks {foo (-> (clojure {:out :string} "-J-Dfoo=\"{:port 5555 :accept clojure.core.server/repl}\" -M -e \"(clojure.edn/read-string (System/getProperty (name :foo)))\"") :out clojure.edn/read-string prn)}})
+ (is (= '{:port 5555, :accept clojure.core.server/repl}
+ (bb "run" "foo")))))
+ (testing "can be called without args"
+ (test-utils/with-config
+ (pr-str '{:tasks {foo (-> (clojure {:in "(+ 1 2 3)" :out :string}) :out prn)}})
+ (is (str/includes? (bb "run" "foo") "6")))
+ ;; can't properly test this, but `(clojure)` should work with zero args
+ #_(test-utils/with-config
+ (pr-str '{:tasks {foo (-> (clojure) :out prn)}})
+ (is (str/includes? (test-utils/bb "(+ 1 2 3)" "run" "foo") "6"))))
+ (testing "call to run in missing dir gives 'cannot run program' message"
+ (test-utils/with-config
+ (pr-str '{:tasks {foo (clojure {:dir "../missingdir"} "-M" "-r")}})
+ ;; check rough text of error message, specific message about missing directory is OS-dependent
+ (is (thrown-with-msg? Exception #"Cannot run program .* \(in directory \"\.\.[/\\]missingdir\"\)"
+ (bb "run" "foo"))))))
+
(deftest list-tasks-test
(test-utils/with-config {}
(let [res (test-utils/bb nil "tasks")]
@@ -319,7 +340,7 @@
(test-utils/with-config '{:tasks {abc 1 xyz 2}}
(let [res (test-utils/bb nil "tasks")]
(is (= "The following tasks are available:\n\nabc\nxyz\n" res))))
- (test-utils/with-config '{:tasks {abc 1 xyz {:doc "some text" :tasks 5}
+ (test-utils/with-config '{:tasks {abc 1 xyz {:doc "some text" :tasks 5}
-xyz 3 qrs {:private true}}}
(let [res (test-utils/bb nil "tasks")]
(is (= "The following tasks are available:\n\nabc\nxyz some text\n" res))))
@@ -366,7 +387,7 @@ even more stuff here\"
(try
(spit "uberjar" "#!/usr/bin/env bb\n(+ 1 2 3)")
(vreset! common/bb-edn '{:tasks {uberjar (+ 1 2 3)}})
- (is (= "uberjar" (:file (main/parse-opts ["uberjar"]))))
+ (is (= {:file "uberjar", :command-line-args '("--version")} (second (main/parse-opts ["uberjar" "--version"]))))
(finally (fs/delete "uberjar"))))))
(deftest min-bb-version-test
@@ -375,7 +396,7 @@ even more stuff here\"
(spit config '{:min-bb-version "300.0.0"})
(let [sw (java.io.StringWriter.)]
(binding [*err* sw]
- (main/main "--config" config "-e" "nil"))
+ (main/main "--config" config "-e" "nil"))
(is (str/includes? (str sw)
"WARNING: this project requires babashka 300.0.0 or newer, but you have: "))))))
@@ -388,7 +409,7 @@ even more stuff here\"
entries (cp/split-classpath out)
entry (first entries)]
(is (= 1 (count entries)))
- (is (= (fs/parent config) (fs/parent entry)))
+ (is (= (fs/real-path (fs/parent config)) (fs/real-path (fs/parent entry))))
(is (str/ends-with? entry "src"))))))
(deftest without-deps-test
@@ -455,9 +476,9 @@ even more stuff here\"
(when (= "amd64" (System/getProperty "os.arch")) ; TODO: Build bootleg for aarch64 too or use a different pod
(test-utils/with-config
(pr-str '{:paths ["test-resources"]
- :pods {retrogradeorbit/bootleg {:version "0.1.9"}}})
+ :pods {retrogradeorbit/bootleg {:version "0.1.9"}}})
(is (= "\"\"\n"
- (test-utils/bb nil "-m" "pod-tests.bootleg"))))))
+ (test-utils/bb nil "--prn" "-m" "pod-tests.bootleg"))))))
(deftest ^:skip-windows local-pod-test
(test-utils/with-config
@@ -476,3 +497,47 @@ even more stuff here\"
"{:deps {}}"
(is (= {1 {:a 1}}
(bb "-Sdeps" "{:deps {medley/medley {:mvn/version \"1.4.0\"}}}" "-e" "(require 'medley.core) (medley.core/index-by :a [{:a 1}])")))))
+
+(deftest deps-root-test
+ (fs/with-temp-dir [dir {}]
+ (let [f (fs/file dir "bb.edn")
+ config (str f)]
+ (spit config
+ '{:paths ["src"]
+ :tasks {cp (prn (babashka.classpath/get-classpath))}})
+ (testing "custom deps-root path"
+ (let [out (bb "--config" config "--deps-root" (str dir) "cp")
+ entries (cp/split-classpath out)]
+ (is (= 1 (count entries)))
+ (is (= (fs/file dir "src") (fs/file (first entries))))))
+ (testing "default deps-root path is same as bb.edn"
+ (let [out (bb "--config" config "cp")
+ entries (cp/split-classpath out)]
+ (is (= (fs/real-path(fs/parent f)) (fs/real-path (fs/parent (first entries)))))))
+ (spit config
+ '{:paths ["src"]
+ :deps {local/dep {:local/root "local-dep"}}
+ :tasks {cp (prn (babashka.classpath/get-classpath))}})
+ (testing "relative paths in deps should be relative to bb.edn"
+ (let [root (fs/create-dir (fs/file dir "local-dep"))
+ _ (spit (str (fs/file root "deps.edn")) {})
+ out (bb "--config" config "cp")
+ entries (cp/split-classpath out)]
+ (is (= (fs/real-path (fs/parent f)) (fs/real-path (fs/parent (first entries))))))))))
+
+(deftest adjacent-bb-edn-test
+ (is (= {1 {:id 1}} (bb "test-resources/adjacent_bb/medley.bb")))
+ (is (= {1 {:id 1}} (bb "-f" "test-resources/adjacent_bb/medley.bb")))
+ (testing "symlink"
+ (is (= {1 {:id 1}} (bb (str (fs/file "test-resources" "symlink-adjacent-bb")))))))
+
+(deftest non-existing-tasks-in-run-gives-exit-code-1
+ (is (thrown? Exception (bb "-Sdeps" "{:tasks {foo {:task (run (quote bar))}}}" "foo"))))
+
+(deftest empty-bb-edn-test
+ (is (= 6 (bb "-Sdeps" "" "-e" "(+ 1 2 3)"))))
+
+(deftest warning-on-override-task
+ (when-not test-utils/native?
+ (binding [*out* *err*]
+ (is (str/includes? (with-out-str (bb "-Sdeps" "{:tasks {run {:task 1}}}" "run")) "'run' override")))))
diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj
index ae04e945..dbdaaa3a 100644
--- a/test/babashka/classpath_test.clj
+++ b/test/babashka/classpath_test.clj
@@ -13,12 +13,12 @@
(deftest classpath-test
(is (= :my-script/bb
- (bb nil "--classpath" "test-resources/babashka/src_for_classpath_test"
+ (bb nil "--prn" "--classpath" "test-resources/babashka/src_for_classpath_test"
"(require '[my-script :as ms]) (ms/foo)")))
(is (= "hello from foo\n"
- (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
+ (tu/bb nil "--prn" "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
"(require '[foo :as f]) (f/foo)")))
- (is (thrown-with-msg? Exception #"not find"
+ (is (thrown-with-msg? Exception #"not locate"
(tu/bb nil
"(require '[foo :as f])"))))
@@ -42,10 +42,10 @@
(deftest main-test
(is (= "(\"1\" \"2\" \"3\" \"4\")\n"
- (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main" "1" "2" "3" "4")))
+ (tu/bb nil "--prn" "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main" "1" "2" "3" "4")))
(testing "system property"
(is (= "\"my.main2\""
- (str/trim (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main2"))))))
+ (str/trim (tu/bb nil "--prn" "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main2"))))))
(deftest error-while-loading-test
(is (true?
@@ -70,3 +70,20 @@
(str/trim
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
"(pos? (count (slurp (io/resource \"foo.clj\")))) "))))))
+
+(deftest classloader-test
+ (let [url
+ (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
+ "(first (map str (.getURLs (clojure.lang.RT/baseLoader))))")]
+ (is (str/includes? url "file:"))
+ (is (str/includes? url "foo.jar")))
+ (let [results (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
+ "(map some? [(.getResource (clojure.lang.RT/baseLoader) \"foo.clj\")
+ (.getResourceAsStream (clojure.lang.RT/baseLoader) \"foo.clj\")
+ (.getResources (clojure.lang.RT/baseLoader) \"foo.clj\")])")]
+ (is (= [true true true] (edn/read-string results)))))
+
+(deftest reader-tag-test
+ (is (= [[3 2 1] [1 2 3]]
+ (bb nil "--classpath" "test-resources/babashka/src_for_classpath_test"
+ "(require 'reader) [#r/reverse [1 2 3] #r/distinct [1 1 2 3]]"))))
diff --git a/test/babashka/crypto_test.clj b/test/babashka/crypto_test.clj
index 48503f69..22141991 100644
--- a/test/babashka/crypto_test.clj
+++ b/test/babashka/crypto_test.clj
@@ -34,3 +34,19 @@
(String. (.encode (java.util.Base64/getEncoder)
(hmac-sha-256 (.getBytes key-s) data))
"utf-8"))))))))
+
+(deftest secretkey-test
+ (is (= 32 (bb '(do (import 'javax.crypto.SecretKeyFactory)
+ (import 'javax.crypto.spec.PBEKeySpec)
+
+ (defn gen-secret-key
+ "Generate secret key based on a given token string.
+ Returns bytes array 256-bit length."
+ [^String secret-token]
+ (let [salt (.getBytes "abcde")
+ factory (SecretKeyFactory/getInstance "PBKDF2WithHmacSHA256")
+ spec (PBEKeySpec. (.toCharArray secret-token) salt 10000 256)
+ secret (.generateSecret factory spec)]
+ (count (.getEncoded secret))))
+
+ (gen-secret-key "foo"))))))
diff --git a/test/babashka/deps_test.clj b/test/babashka/deps_test.clj
index e130e680..56980e98 100644
--- a/test/babashka/deps_test.clj
+++ b/test/babashka/deps_test.clj
@@ -7,10 +7,11 @@
[clojure.test :as test :refer [deftest is testing]]))
(defn bb [& args]
- (edn/read-string
- {:readers *data-readers*
- :eof nil}
- (apply test-utils/bb nil (map str args))))
+ (let [edn-str (apply test-utils/bb nil (map str args))]
+ (edn/read-string
+ {:readers *data-readers*
+ :eof nil}
+ edn-str)))
(deftest dependency-test
(is (= #{:a :c :b} (bb "
@@ -105,21 +106,21 @@ true
(is (fs/exists? libs-dir2))))))
(deftest ^:windows-only win-clojure-test
- (testing "GITLIBS can set location of .gitlibs dir"
- (let [tmp-dir (fs/create-temp-dir)
- libs-dir (fs/file tmp-dir ".gitlibs")
- libs-dir2 (fs/file tmp-dir ".gitlibs2")
+ (testing "GITLIBS can set location of .gitlibs dir"
+ (let [tmp-dir (fs/create-temp-dir)
+ libs-dir (fs/file tmp-dir ".gitlibs")
+ libs-dir2 (fs/file tmp-dir ".gitlibs2")
; nested quotes need different escaping for Windows based on jvm/native test
- escape-quote (if test-utils/native? "\\\\\"" "\\\"")
- deps-map (str/join escape-quote [" \"{:deps {babashka/process {:git/url "
- "https://github.com/babashka/process" " :sha "
- "4c6699d06b49773d3e5c5b4c11d3334fb78cc996" "}}}\""])
- template (str "(do (babashka.deps/clojure [\"-Sforce\" \"-Spath\" \"-Sdeps\"" deps-map "]
+ escape-quote (if test-utils/native? "\\\\\"" "\\\"")
+ deps-map (str/join escape-quote [" \"{:deps {babashka/process {:git/url "
+ "https://github.com/babashka/process" " :sha "
+ "4c6699d06b49773d3e5c5b4c11d3334fb78cc996" "}}}\""])
+ template (str "(do (babashka.deps/clojure [\"-Sforce\" \"-Spath\" \"-Sdeps\"" deps-map "]
{:out :string :env-key {\"PATH\" (System/getenv \"PATH\")
\"GITLIBS\" :gitlibs}}) nil)")]
- (bb (-> template (str/replace ":gitlibs" (pr-str (str libs-dir)))
+ (bb (-> template (str/replace ":gitlibs" (pr-str (str libs-dir)))
(str/replace ":env-key" ":env")))
- (bb (-> template (str/replace ":gitlibs" (pr-str (str libs-dir2)))
+ (bb (-> template (str/replace ":gitlibs" (pr-str (str libs-dir2)))
(str/replace ":env-key" ":extra-env")))
- (is (fs/exists? libs-dir))
- (is (fs/exists? libs-dir2)))))
+ (is (fs/exists? libs-dir))
+ (is (fs/exists? libs-dir2)))))
diff --git a/test/babashka/error_test.clj b/test/babashka/error_test.clj
index e82a7175..e79967b3 100644
--- a/test/babashka/error_test.clj
+++ b/test/babashka/error_test.clj
@@ -7,13 +7,19 @@
[clojure.test :as t :refer [deftest is testing]]
[matcher-combinators.test]))
+(defn process-difference [line]
+ (-> line str/trimr
+ ;; take into account JDK14+ and native image differences
+ (str/replace "class clojure.lang" "clojure.lang")
+ (str/replace #" \(.*\)$" "")))
+
(defmacro multiline-equals [s1 s2]
`(let [lines-s1# (str/split-lines ~s1)
lines-s2# (str/split-lines ~s2)
max-lines# (max (count lines-s1#) (count lines-s2#))
lines-s1# (take max-lines# lines-s1#)
lines-s2# (take max-lines# lines-s2#)]
- (is (~'match? (map str/trimr lines-s1#) (map str/trimr lines-s2#)))
+ (is (~'match? (map process-difference lines-s1#) (map process-difference lines-s2#)))
#_(run! (fn [i]
(let [l1 (get lines-s1 i)
l2 (get lines-s2 i)]
@@ -117,58 +123,63 @@ user - :1:1")))))
(deftest error-while-macroexpanding-test
- (let [output (try (tu/bb nil "-e" "(defmacro foo [x] (subs nil 1) `(do ~x ~x)) (foo 1)")
+ (let [output (try (tu/bb nil "-e" "(defmacro foo [x] (assoc :foo 1 2) `(do ~x ~x)) (foo 1)")
(catch Exception e (ex-message e)))]
(multiline-equals output
"----- Error --------------------------------------------------------------------
-Type: java.lang.NullPointerException
+Type: java.lang.ClassCastException
+Message: clojure.lang.Keyword cannot be cast to clojure.lang.Associative
Location: :1:19
Phase: macroexpand
----- Context ------------------------------------------------------------------
-1: (defmacro foo [x] (subs nil 1) `(do ~x ~x)) (foo 1)
- ^---
+1: (defmacro foo [x] (assoc :foo 1 2) `(do ~x ~x)) (foo 1)
+ ^--- clojure.lang.Keyword cannot be cast to clojure.lang.Associative
----- Stack trace --------------------------------------------------------------
-clojure.core/subs -
-user/foo - :1:19
-user/foo - :1:1
-user - :1:45")))
+clojure.core/assoc--5481 -
+clojure.core/assoc -
+user/foo - :1:19
+user/foo - :1:1
+user - :1:49")))
(deftest error-in-macroexpansion-test
- (let [output (try (tu/bb nil "-e" "(defmacro foo [x] `(subs nil ~x)) (foo 1)")
+ (let [output (try (tu/bb nil "-e" "(defmacro foo [x] `(assoc :foo ~x 2)) (foo 1)")
(catch Exception e (ex-message e)))]
(multiline-equals output
"----- Error --------------------------------------------------------------------
-Type: java.lang.NullPointerException
-Location: :1:35
+Type: java.lang.ClassCastException
+Message: clojure.lang.Keyword cannot be cast to clojure.lang.Associative
+Location: :1:39
----- Context ------------------------------------------------------------------
-1: (defmacro foo [x] `(subs nil ~x)) (foo 1)
- ^---
+1: (defmacro foo [x] `(assoc :foo ~x 2)) (foo 1)
+ ^--- clojure.lang.Keyword cannot be cast to clojure.lang.Associative
----- Stack trace --------------------------------------------------------------
-clojure.core/subs -
-user - :1:35
-"))
+clojure.core/assoc--5481 -
+clojure.core/assoc -
+user - :1:39"))
(testing "calling a var inside macroexpansion"
- (let [output (try (tu/bb nil "-e" "(defn quux [] (subs nil 1)) (defmacro foo [x & xs] `(do (quux) ~x)) (defn bar [] (foo 1)) (bar)")
+ (let [output (try (tu/bb nil "-e" "(defn quux [] (assoc :foo 1 2)) (defmacro foo [x & xs] `(do (quux) ~x)) (defn bar [] (foo 1)) (bar)")
(catch Exception e (ex-message e)))]
(multiline-equals output
"----- Error --------------------------------------------------------------------
-Type: java.lang.NullPointerException
+Type: java.lang.ClassCastException
+Message: clojure.lang.Keyword cannot be cast to clojure.lang.Associative
Location: :1:15
----- Context ------------------------------------------------------------------
-1: (defn quux [] (subs nil 1)) (defmacro foo [x & xs] `(do (quux) ~x)) (defn bar [] (foo 1)) (bar)
- ^---
+1: (defn quux [] (assoc :foo 1 2)) (defmacro foo [x & xs] `(do (quux) ~x)) (defn bar [] (foo 1)) (bar)
+ ^--- clojure.lang.Keyword cannot be cast to clojure.lang.Associative
----- Stack trace --------------------------------------------------------------
-clojure.core/subs -
-user/quux - :1:15
-user/quux - :1:1
-user/bar - :1:69
-user - :1:91"))))
+clojure.core/assoc--5481 -
+clojure.core/assoc -
+user/quux - :1:15
+user/quux - :1:1
+user/bar - :1:73
+user - :1:95"))))
(deftest print-exception-data-test
(testing "output of uncaught ExceptionInfo"
@@ -232,29 +243,31 @@ clojure.lang.ExceptionInfo: Divide by zero")))
"{:type :sci/error, :line 1, :column 12, :message \"Divide by zero\",")))))
(deftest macro-test
- (let [output (try (tu/bb nil "--debug" "(defmacro foo [x] (subs nil 1) `(do ~x ~x)) (foo 1)")
+ (let [output (try (tu/bb nil "--debug" "(defmacro foo [x] (assoc :foo 1 2) `(do ~x ~x)) (foo 1)")
(is false)
(catch Exception e (ex-message e)))
output (tu/normalize output)
- actual-lines (str/join "\n" (take 17 (str/split-lines output)))]
+ actual-lines (str/join "\n" (take 19 (str/split-lines output)))]
(multiline-equals actual-lines
"----- Error --------------------------------------------------------------------
-Type: java.lang.NullPointerException
+Type: java.lang.ClassCastException
+Message: clojure.lang.Keyword cannot be cast to clojure.lang.Associative
Location: :1:19
Phase: macroexpand
----- Context ------------------------------------------------------------------
-1: (defmacro foo [x] (subs nil 1) `(do ~x ~x)) (foo 1)
- ^---
+1: (defmacro foo [x] (assoc :foo 1 2) `(do ~x ~x)) (foo 1)
+ ^--- clojure.lang.Keyword cannot be cast to clojure.lang.Associative
----- Stack trace --------------------------------------------------------------
-clojure.core/subs -
-user/foo - :1:19
-user/foo - :1:1
-user - :1:45
+clojure.core/assoc--5481 -
+clojure.core/assoc -
+user/foo - :1:19
+user/foo - :1:1
+user - :1:49
----- Exception ----------------------------------------------------------------
-clojure.lang.ExceptionInfo: null")))
+clojure.lang.ExceptionInfo: clojure.lang.Keyword cannot be cast to clojure.lang.Associative")))
(deftest native-stacktrace-test
(let [output (try (tu/bb nil "(merge 1 2 3)")
diff --git a/test/babashka/exec_test.clj b/test/babashka/exec_test.clj
index 4a990520..69d13659 100644
--- a/test/babashka/exec_test.clj
+++ b/test/babashka/exec_test.clj
@@ -11,9 +11,11 @@
(deftest exec-test
(is (= {:foo 1} (edn/read-string (bb "-x" "prn" "--foo" "1"))))
(is (thrown? Exception (bb "-x" "json/generate-string" "--foo" "1")))
+ (is (thrown-with-msg? Exception #"Could not resolve sym to a function: clojure.core/generate-string"
+ (bb "-x" "clojure.core/generate-string" "--foo" "1")))
(is (= {:foo 1} (cheshire/parse-string
(edn/read-string
- (bb "-x" "cheshire.core/generate-string" "--foo" "1")) true))))
+ (bb "--prn" "-x" "cheshire.core/generate-string" "--foo" "1")) true))))
(deftest tasks-exec-test
(u/with-config
@@ -37,8 +39,13 @@
(testing "task exec args"
(u/with-config
"{:deps {}
- :tasks {foo {:exec-args {:foo :bar}
- :task (exec 'babashka.exec-test/exec-test)}}}"
+ :tasks {foo {:task (exec 'babashka.exec-test/exec-test)}}}"
+ (is (= {:foo :foo, :bar :yeah}
+ (edn/read-string (bb "-cp" "test-resources" "run" "foo" "--bar" "yeah")))))
+ (u/with-config
+ "{:deps {}
+ :tasks {foo {:exec-args {:foo :bar}
+ :task (exec 'babashka.exec-test/exec-test)}}}"
(is (= {:foo :bar, :bar :yeah}
(edn/read-string (bb "-cp" "test-resources" "run" "foo" "--bar" "yeah"))))))
(testing "meta"
diff --git a/test/babashka/file_var_test.clj b/test/babashka/file_var_test.clj
index e601523a..bc5d058b 100644
--- a/test/babashka/file_var_test.clj
+++ b/test/babashka/file_var_test.clj
@@ -10,7 +10,7 @@
(deftest file-var-test
(let [[f1 f2 f3 f4]
- (str/split (bb nil "--classpath" "test/babashka/scripts"
+ (str/split (bb nil "--prn" "--classpath" "test/babashka/scripts"
"test/babashka/scripts/file_var.bb")
#"\n")]
(is (str/ends-with? f1 "file_var_classpath.bb"))
@@ -19,6 +19,6 @@
(is (str/ends-with? f4 "file_var.bb")))
(testing "file var uses absolute path"
(is (str/includes?
- (bb nil (io/file "test" ".." "test"
- "babashka" "scripts" "simple_file_var.bb"))
+ (bb nil "--prn" (io/file "test" ".." "test"
+ "babashka" "scripts" "simple_file_var.bb"))
".."))))
diff --git a/test/babashka/http_connection_test.clj b/test/babashka/http_connection_test.clj
index 25a5338e..b3247c1d 100644
--- a/test/babashka/http_connection_test.clj
+++ b/test/babashka/http_connection_test.clj
@@ -7,7 +7,7 @@
(defn bb [& args]
(apply tu/bb nil (map str args)))
-(deftest open-connection-test
+(deftest ^:flaky open-connection-test
(is (try (= "\"1\"" (str/trim (bb "-e" "
(require '[cheshire.core :as json])
(let [conn ^java.net.HttpURLConnection (.openConnection (java.net.URL. \"https://postman-echo.com/get?foo=1\"))]
diff --git a/test/babashka/impl/clojure/java/browse_test.clj b/test/babashka/impl/clojure/java/browse_test.clj
new file mode 100644
index 00000000..83ee3fb1
--- /dev/null
+++ b/test/babashka/impl/clojure/java/browse_test.clj
@@ -0,0 +1,25 @@
+(ns babashka.impl.clojure.java.browse-test
+ #_(:require
+ [babashka.test-utils :refer [bb]]
+ [cheshire.core :as json]
+ [clojure.test :refer [deftest is]]
+ [org.httpkit.server :as http]))
+
+(def ^:dynamic *http-port* 1234)
+
+#_(deftest browse-url-test
+ (let [p (promise)
+ stop-server (http/run-server (fn [{:keys [query-string]}]
+ (let [params (apply hash-map (mapcat #(.split % "=") (.split query-string "&")))]
+ (deliver p params)
+ {:status 200
+ :content-type "application/json"
+ :body (json/encode params)}))
+ {:port *http-port*})]
+ (try
+ (bb nil
+ (str "(clojure.java.browse/browse-url \"http://localhost:" *http-port* "?arg1=v1&arg2=v2\")"))
+ (is (= {"arg1" "v1"
+ "arg2" "v2"}
+ (deref p 5000 ::timeout)))
+ (finally (stop-server :timeout 1000)))))
diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj
index 04946085..108cc123 100644
--- a/test/babashka/impl/nrepl_server_test.clj
+++ b/test/babashka/impl/nrepl_server_test.clj
@@ -1,13 +1,18 @@
(ns babashka.impl.nrepl-server-test
(:require
+ [babashka.fs :as fs]
+ [babashka.impl.nrepl-server :refer [start-server!]]
[babashka.main :as main]
- [babashka.nrepl.server :refer [start-server! stop-server! parse-opt]]
+ [babashka.nrepl.server :refer [parse-opt stop-server!]]
[babashka.test-utils :as tu]
[babashka.wait :as wait]
[bencode.core :as bencode]
[clojure.test :as t :refer [deftest is testing]]
- [sci.impl.opts :refer [init]])
- (:import [java.lang ProcessBuilder$Redirect]))
+ [sci.core :as sci]
+ [sci.ctx-store :as ctx-store]
+ [babashka.impl.classpath :as cp])
+ (:import
+ [java.lang ProcessBuilder$Redirect]))
(def debug? false)
@@ -28,6 +33,9 @@
res)
res (if-let [status (:sessions res)]
(assoc res :sessions (mapv bytes->str status))
+ res)
+ res (if-let [cp (:classpath res)]
+ (assoc res :classpath (mapv bytes->str cp))
res)]
res))
@@ -59,9 +67,11 @@
(let [msg (read-reply in session @id)
id (:id msg)
versions (:versions msg)
- babashka-version (bytes->str (get versions "babashka"))]
+ babashka-version (bytes->str (get versions "babashka"))
+ ops (:ops msg)]
(is (= 1 id))
- (is (= main/version babashka-version))))
+ (is (= main/version babashka-version))
+ (is (contains? ops "classpath"))))
(testing "eval"
(bencode/write-bencode os {"op" "eval" "code" "(+ 1 2 3)" "session" session "id" (new-id!)})
(let [msg (read-reply in session @id)
@@ -87,13 +97,13 @@
(is (= ":foo0" (:value (read-reply in session @id)))))
;; TODO: I don't remember why we created a new ns
#_(testing "providing an ns value of a non-existing namespace creates the namespace"
- (bencode/write-bencode os {"op" "eval"
- "code" "(ns-name *ns*)"
- "session" session
- "id" (new-id!)
- "ns" "unicorn"})
- (let [reply (read-reply in session @id)]
- (is (= "unicorn" (:value reply))))))
+ (bencode/write-bencode os {"op" "eval"
+ "code" "(ns-name *ns*)"
+ "session" session
+ "id" (new-id!)
+ "ns" "unicorn"})
+ (let [reply (read-reply in session @id)]
+ (is (= "unicorn" (:value reply))))))
(testing "multiple top level expressions results in two value replies"
(bencode/write-bencode os {"op" "eval"
"code" "(+ 1 2 3) (+ 1 2 3)"
@@ -181,37 +191,53 @@
"session" session "id" (new-id!)})
(dotimes [_ 3]
(let [reply (read-reply in session @id)]
- (is (= "Hello\n" (tu/normalize (:out reply))))))))))
+ (is (= "Hello\n" (tu/normalize (:out reply)))))))
+ (testing "dynamic var can be set!, test unchecked-math"
+ (bencode/write-bencode os {"op" "eval" "code" "(set! *unchecked-math* true)"
+ "session" session "id" (new-id!)})
+ (let [reply (read-reply in session @id)]
+ (is (= "true" (:value reply)))))
+ (testing "classpath op"
+ (bencode/write-bencode os {"op" "eval" "code" "(babashka.classpath/add-classpath \"test-resources/babashka/src_for_classpath_test\")"
+ "session" session "id" (new-id!)})
+ (read-reply in session @id)
+ (bencode/write-bencode os {"op" "classpath"
+ "session" session "id" (new-id!)})
+ (let [reply (read-reply in session @id)
+ cp (:classpath reply)]
+ (is (every? string? cp))
+ (is (pos? (count cp)))
+ ;; dev-resources doesn't exist
+ (is (pos? (count (filter fs/exists? cp)))))))))
(deftest ^:skip-windows nrepl-server-test
(let [proc-state (atom nil)
- server-state (atom nil)]
- (try
- (if tu/jvm?
- (let [nrepl-opts (parse-opt "0.0.0.0:1668")
- nrepl-opts (assoc nrepl-opts
- :describe {"versions" {"babashka" main/version}})
- server (start-server!
- (init {:namespaces main/namespaces
- :features #{:bb}})
- nrepl-opts)]
- (reset! server-state server))
- (let [pb (ProcessBuilder. ["./bb" "nrepl-server" "0.0.0.0:1668"])
- _ (.redirectError pb ProcessBuilder$Redirect/INHERIT)
- ;; _ (.redirectOutput pb ProcessBuilder$Redirect/INHERIT)
- ;; env (.environment pb)
- ;; _ (.put env "BABASHKA_DEV" "true")
- proc (.start pb)]
- (reset! proc-state proc)))
- (babashka.wait/wait-for-port "localhost" 1668)
- (nrepl-test)
- (finally
+ server-state (atom nil)
+ ctx (sci/init {:namespaces main/namespaces
+ :features #{:bb}})]
+ (sci.ctx-store/with-ctx ctx
+ (try
(if tu/jvm?
- (stop-server! @server-state)
- (when-let [proc @proc-state]
- (.destroy ^Process proc)))))))
+ (let [nrepl-opts (parse-opt "0.0.0.0:1668")
+ nrepl-opts (assoc nrepl-opts
+ :describe {"versions" {"babashka" main/version}})
+ server (start-server! nrepl-opts)]
+ (reset! server-state server))
+ (let [pb (ProcessBuilder. ["./bb" "nrepl-server" "0.0.0.0:1668"])
+ _ (.redirectError pb ProcessBuilder$Redirect/INHERIT)
+ ;; _ (.redirectOutput pb ProcessBuilder$Redirect/INHERIT)
+ ;; env (.environment pb)
+ ;; _ (.put env "BABASHKA_DEV" "true")
+ proc (.start pb)]
+ (reset! proc-state proc)))
+ (babashka.wait/wait-for-port "localhost" 1668)
+ (nrepl-test)
+ (finally
+ (if tu/jvm?
+ (stop-server! @server-state)
+ (when-let [proc @proc-state]
+ (.destroy ^Process proc))))))))
;;;; Scratch
-(comment
- )
+(comment)
diff --git a/test/babashka/impl/socket_repl_test.clj b/test/babashka/impl/socket_repl_test.clj
index 5699b456..ba94da9d 100644
--- a/test/babashka/impl/socket_repl_test.clj
+++ b/test/babashka/impl/socket_repl_test.clj
@@ -1,8 +1,8 @@
(ns babashka.impl.socket-repl-test
(:require
- [babashka.impl.common :as common]
[babashka.impl.server :refer [clojure-core-server-namespace]]
[babashka.impl.socket-repl :refer [start-repl! stop-repl!]]
+ [babashka.main :as main]
[babashka.process :as p]
[babashka.test-utils :as tu]
[babashka.wait :as w]
@@ -15,115 +15,122 @@
(set! *warn-on-reflection* true)
-(defn socket-command [expr expected]
- (with-open [socket (java.net.Socket. "127.0.0.1" 1666)
- reader (io/reader socket)
- sw (java.io.StringWriter.)
- writer (io/writer socket)]
- (binding [*out* writer]
- (println (str expr "\n")))
- (loop []
- (when-let [l (try (.readLine ^java.io.BufferedReader reader)
- (catch java.net.SocketException _ nil))]
- ;; (prn :l l)
- (binding [*out* sw]
- (println l))
- (let [s (str sw)]
- ;; (prn :s s :expected expected (str/includes? s expected))
- (if (if (fn? expected)
- (expected s)
- (str/includes? s expected))
- (is true)
- (recur)))))
- (binding [*out* writer]
- (println ":repl/quit\n"))
- :success))
+(defn socket-command-on-port [^long port]
+ (fn [expr expected & [log?]]
+ (with-open [socket (java.net.Socket. "127.0.0.1" port)
+ reader (io/reader socket)
+ sw (java.io.StringWriter.)
+ writer (io/writer socket)]
+ (binding [*out* writer]
+ (println (str expr "\n")))
+ (loop []
+ (when-let [l (try (.readLine ^java.io.BufferedReader reader)
+ (catch java.net.SocketException _ nil))]
+ (when log?
+ (println "===" l))
+ (binding [*out* sw]
+ (println l))
+ (let [s (str sw)]
+ ;; (prn :s s :expected expected (str/includes? s expected))
+ (if (if (fn? expected)
+ (expected s)
+ (str/includes? s expected))
+ (is true)
+ (recur)))))
+ (binding [*out* writer]
+ (println ":repl/quit\n"))
+ :success)))
(def server-process (volatile! nil))
(def exec? (System/getenv "BABASHKA_SOCKET_REPL_TEST"))
-(deftest socket-repl-test
+(deftest ^:flaky socket-repl-test
(when exec?
- (try
- (if tu/jvm?
- (let [ctx (init {:namespaces {'clojure.core.server clojure-core-server-namespace}
- :features #{:bb}})]
- (ctx-store/reset-ctx! ctx)
- (start-repl! "0.0.0.0:1666" ctx))
- (do (vreset! server-process
- (p/process ["./bb" "socket-repl" "localhost:1666"]))
- (w/wait-for-port "localhost" 1666)))
- (Thread/sleep 50)
- (is (socket-command "(+ 1 2 3)" "user=> 6"))
- (testing "&env"
- (socket-command "(defmacro bindings [] (mapv #(list 'quote %) (keys &env)))" "bindings")
- (socket-command "(defn bar [x y z] (bindings))" "bar")
- (is (socket-command "(bar 1 2 3)" "[x y z]")))
- (testing "reader conditionals"
- (is (socket-command "#?(:bb 1337 :clj 8888)" "1337")))
- (testing "*1, *2, *3, *e"
- (is (socket-command "1\n*1" "1")))
- (testing "*ns*"
- (is (socket-command "(ns foo.bar) (ns-name *ns*)" "foo.bar")))
- (finally
+ (let [socket-command (socket-command-on-port 1666)]
+ (try
(if tu/jvm?
- (do (stop-repl!)
- (ctx-store/reset-ctx! nil)
- (Thread/sleep 100))
- (p/destroy-tree @server-process))))))
+ (let [ctx (init {:namespaces main/namespaces
+ :features #{:bb}})]
+ (ctx-store/reset-ctx! ctx)
+ (start-repl! "0.0.0.0:1666" ctx))
+ (do (vreset! server-process
+ (p/process ["./bb" "socket-repl" "localhost:1666"]))
+ (w/wait-for-port "localhost" 1666)))
+ (Thread/sleep 50)
+ (is (socket-command "(+ 1 2 3)" "user=> 6"))
+ (testing "&env"
+ (socket-command "(defmacro bindings [] (mapv #(list 'quote %) (keys &env)))" "bindings")
+ (socket-command "(defn bar [x y z] (bindings))" "bar")
+ (is (socket-command "(bar 1 2 3)" "[x y z]")))
+ (testing "reader conditionals"
+ (is (socket-command "#?(:bb 1337 :clj 8888)" "1337")))
+ (testing "*1, *2, *3, *e"
+ (is (socket-command "1\n*1" "1")))
+ (testing "*ns*"
+ (is (socket-command "(ns foo.bar) (ns-name *ns*)" "foo.bar")))
+ (testing "set dyn vars"
+ (is (socket-command "[(set! *warn-on-reflection* true) (set! *unchecked-math* true)]" "[true true]")))
+ (finally
+ (if tu/jvm?
+ (do (stop-repl!)
+ (ctx-store/reset-ctx! nil)
+ (Thread/sleep 100))
+ (p/destroy-tree @server-process)))))))
-(deftest socket-repl-opts-test
+(deftest ^:flaky socket-repl-opts-test
(when exec?
- (try
- (if tu/jvm?
- (let [ctx (init {:bindings {'*command-line-args*
- ["a" "b" "c"]}
- :env (atom {})
- :namespaces {'clojure.core.server clojure-core-server-namespace}
- :features #{:bb}})]
- (ctx-store/reset-ctx! ctx)
- (start-repl! "{:address \"localhost\" :accept clojure.core.server/repl :port 1666}"
- ctx))
- (do (vreset! server-process
- (p/process ["./bb" "--socket-repl" "{:address \"localhost\" :accept clojure.core.server/repl :port 1666}"]))
- (w/wait-for-port "localhost" 1666)))
- (Thread/sleep 50)
- (is (socket-command "(+ 1 2 3)" "user=> 6"))
- (finally
- (if tu/jvm?
- (do (stop-repl!)
- (ctx-store/reset-ctx! nil)
- (Thread/sleep 100))
- (p/destroy-tree @server-process))))))
+ (let [socket-command (socket-command-on-port 1667)]
+ (try
+ (if tu/jvm?
+ (let [ctx (init {:bindings {'*command-line-args*
+ ["a" "b" "c"]}
+ :env (atom {})
+ :namespaces {'clojure.core.server clojure-core-server-namespace}
+ :features #{:bb}})]
+ (ctx-store/reset-ctx! ctx)
+ (start-repl! "{:address \"localhost\" :accept clojure.core.server/repl :port 1667}"
+ ctx))
+ (do (vreset! server-process
+ (p/process ["./bb" "--socket-repl" "{:address \"localhost\" :accept clojure.core.server/repl :port 1667}"]))
+ (w/wait-for-port "localhost" 1667)))
+ (Thread/sleep 50)
+ (is (socket-command "(+ 1 2 3)" "user=> 6"))
+ (finally
+ (if tu/jvm?
+ (do (stop-repl!)
+ (ctx-store/reset-ctx! nil)
+ (Thread/sleep 100))
+ (p/destroy-tree @server-process)))))))
-(deftest socket-prepl-test
+(deftest ^:flaky socket-prepl-test
(when exec?
- (try
- (if tu/jvm?
- (let [ctx (init {:bindings {'*command-line-args*
- ["a" "b" "c"]}
- :env (atom {})
- :namespaces {'clojure.core.server clojure-core-server-namespace}
- :features #{:bb}})]
- (ctx-store/reset-ctx! ctx)
- (start-repl! "{:address \"localhost\" :accept clojure.core.server/io-prepl :port 1666}"
- ctx))
- (do (vreset! server-process
- (p/process ["./bb" "--socket-repl" "{:address \"localhost\" :accept clojure.core.server/io-prepl :port 1666}"]))
- (w/wait-for-port "localhost" 1666)))
- (Thread/sleep 50)
- (is (socket-command "(+ 1 2 3)" (fn [s]
- (let [m (edn/read-string s)]
- (and (= "6" (:val m))
- (= "user" (:ns m))
- (= "(+ 1 2 3)" (:form m)))))))
- (finally
- (if tu/jvm?
- (do (stop-repl!)
- (ctx-store/reset-ctx! nil)
- (Thread/sleep 100))
- (p/destroy-tree @server-process))))))
+ (let [socket-command (socket-command-on-port 1668)]
+ (try
+ (if tu/jvm?
+ (let [ctx (init {:bindings {'*command-line-args*
+ ["a" "b" "c"]}
+ :env (atom {})
+ :namespaces {'clojure.core.server clojure-core-server-namespace}
+ :features #{:bb}})]
+ (ctx-store/reset-ctx! ctx)
+ (start-repl! "{:address \"localhost\" :accept clojure.core.server/io-prepl :port 1668}"
+ ctx))
+ (do (vreset! server-process
+ (p/process ["./bb" "--socket-repl" "{:address \"localhost\" :accept clojure.core.server/io-prepl :port 1668}"]))
+ (w/wait-for-port "localhost" 1668)))
+ (Thread/sleep 50)
+ (is (socket-command "(+ 1 2 3)" (fn [s]
+ (let [m (edn/read-string s)]
+ (and (= "6" (:val m))
+ (= "user" (:ns m))
+ (= "(+ 1 2 3)" (:form m)))))))
+ (finally
+ (if tu/jvm?
+ (do (stop-repl!)
+ (ctx-store/reset-ctx! nil)
+ (Thread/sleep 100))
+ (p/destroy-tree @server-process)))))))
;;;; Scratch
@@ -138,5 +145,5 @@
'*command-line-args*
["a" "b" "c"]}
:env (atom {})})
- (socket-command "(+ 1 2 3)" "6")
+ ((socket-command-on-port 1666) "(+ 1 2 3)" "6")
)
diff --git a/test/babashka/interop_test.clj b/test/babashka/interop_test.clj
new file mode 100644
index 00000000..0f537d86
--- /dev/null
+++ b/test/babashka/interop_test.clj
@@ -0,0 +1,57 @@
+(ns babashka.interop-test
+ (:require
+ [babashka.test-utils :as test-utils]
+ [clojure.edn :as edn]
+ [clojure.test :as test :refer [deftest is testing]]))
+
+(defn bb [input & args]
+ (test-utils/normalize
+ (edn/read-string
+ {:readers *data-readers*
+ :eof nil}
+ (apply test-utils/bb (when (some? input) (str input)) (map str args)))))
+
+(deftest vthreads-test
+ (testing "can invoke methods on java.lang.VirtualThread"
+ (is (= "" (bb nil "(set-agent-send-off-executor! (java.util.concurrent.Executors/newVirtualThreadPerTaskExecutor)) @(future (.getName (Thread/currentThread)))"))))
+ (is (= [false true]
+ (bb nil (pr-str '(do
+ (def t (Thread. (fn [])))
+ (def vt (Thread/startVirtualThread (fn [])))
+ [(.isVirtual t) (.isVirtual vt)]))))))
+
+(deftest domain-sockets-test
+ (is (= :success (bb nil (slurp "test-resources/domain_sockets.bb")))))
+
+(deftest map-entry-create-test
+ (is (true? (bb nil "(= (first {1 2})
+ (clojure.lang.MapEntry. 1 2)
+ (clojure.lang.MapEntry/create 1 2))"))))
+
+(deftest X509Certificate-test
+ (is (true? (bb nil "(import java.security.cert.X509Certificate)
+(import java.security.cert.CertificateFactory)
+(require '[clojure.java.io :as io])
+(defn x509-certificate
+ ^X509Certificate
+ [f]
+ (let [input (io/input-stream f)
+ factory (CertificateFactory/getInstance \"X.509\")]
+ (.generateCertificate factory input)))
+(def cert (x509-certificate (io/file \"test-resources/certificate.crt\")))
+(some? (.getSubjectX500Principal cert))
+"))))
+
+(deftest IntStream-test
+ (is (pos? (bb nil "(.count (.codePoints \"woof🐕\"))"))))
+
+(deftest Thread-sleep-test
+ (is (bb nil "(Thread/sleep (/ 1 200))
+ (Thread/sleep (/ 1 200) (/ 1 200))
+ (Thread/sleep (java.time.Duration/ofMillis 1))
+ true")))
+
+(deftest SSL-test
+ (is (= :user/success
+ (bb nil "(try (.createSocket (javax.net.ssl.SSLSocketFactory/getDefault) \"localhost\" 4444) (catch java.net.ConnectException e ::success))")))
+ (is (bb nil " (.startHandshake (.createSocket (javax.net.ssl.SSLSocketFactory/getDefault) \"clojure.org\" 443)) ::success")))
diff --git a/test/babashka/java_net_http_test.clj b/test/babashka/java_net_http_test.clj
index bed2b2c9..dfa8b94f 100644
--- a/test/babashka/java_net_http_test.clj
+++ b/test/babashka/java_net_http_test.clj
@@ -62,7 +62,7 @@
;; HttpClient options
-(deftest authenticator-test
+(deftest ^:flaky authenticator-test
(is (= [401 200]
(bb
'(do
@@ -89,7 +89,7 @@
auth-res (.send auth-client req handler)]
[(.statusCode no-auth-res) (.statusCode auth-res)]))))))
-(deftest cookie-test
+(deftest ^:flaky cookie-test
(is (= []
(bb '(do (ns net
(:import [java.net CookieManager]))
@@ -121,7 +121,7 @@
first
(.getDomain))))))))
-(deftest connect-timeout-test
+(deftest ^:flaky connect-timeout-test
(is (str/includes?
(bb
'(do
@@ -150,7 +150,7 @@
;; can be either java.net.http.HttpConnectTimeoutException or java.net.http.HttpTimeoutException
"TimeoutException")))
-(deftest executor-test
+(deftest ^:flaky executor-test
(is (= 200
(bb
'(do
@@ -172,7 +172,7 @@
res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res)))))))
-(deftest proxy-test
+(deftest ^:flaky proxy-test
(is (= true
(bb
'(do
@@ -210,7 +210,7 @@
res (.send client req (HttpResponse$BodyHandlers/discarding))]
(.statusCode res)))))))
-(deftest redirect-test
+(deftest ^:flaky redirect-test
(let [redirect-prog
(fn [redirect-kind]
(str/replace (str '(do
@@ -244,7 +244,7 @@
(println "Testing redirect never")
(is (= 302 (bb (redirect-prog :never))))))
-(deftest ssl-context-test
+(deftest ^:flaky ssl-context-test
(let [result
(bb
'(do
@@ -336,7 +336,7 @@
;; HttpRequest
-(deftest body-publishers-test
+(deftest ^:flaky body-publishers-test
(is (= true
(bb
'(do
@@ -428,7 +428,7 @@
:data)))))))))
-(deftest request-timeout-test
+(deftest ^:flaky request-timeout-test
(is (str/includes?
(bb
'(do
@@ -455,7 +455,7 @@
name))))))
"TimeoutException")))
-(deftest body-handlers-test
+(deftest ^:flaky body-handlers-test
(is (= true
(bb
'(do
diff --git a/test/babashka/java_time_test.clj b/test/babashka/java_time_test.clj
index 90d8f704..a2b3ed9a 100644
--- a/test/babashka/java_time_test.clj
+++ b/test/babashka/java_time_test.clj
@@ -2,6 +2,7 @@
(:require
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
+ [clojure.string :as str]
[clojure.test :as test :refer [deftest is]]))
(defn bb [expr]
@@ -17,6 +18,12 @@
(bb '(.format
(java.time.LocalDateTime/parse "2019-12-18T16:01:41.485")
(java.time.format.DateTimeFormatter/ofPattern "dd-MM-yyyy HH:mm:ss")))))
+
+ (let [out (bb '(.format (java.time.LocalDateTime/parse "2019-12-18T16:01:41.485")
+ (java.time.format.DateTimeFormatter/ofLocalizedDateTime java.time.format.FormatStyle/SHORT)))]
+ (is (and (str/includes? out "12") (str/includes? out "18"))))
+
+
(is (number? (bb "
(let [x (java.time.LocalDateTime/parse \"2019-12-18T16:01:41.485\")
y (java.time.LocalDateTime/now)]
diff --git a/test/babashka/logging_test.clj b/test/babashka/logging_test.clj
index 7adb5e9f..18df2046 100644
--- a/test/babashka/logging_test.clj
+++ b/test/babashka/logging_test.clj
@@ -44,7 +44,7 @@
(deftest logging-test
(let [res (tu/bb nil (pr-str program))]
- (is (= 17 (count (re-seq #"\[dude:.\]" res))))
+ (is (= 8 (count (re-seq #"\[dude:.\]" res))))
(is (= 6 (count (re-seq #"DEBUG" res))))
(is (= 11 (count (re-seq #"INFO" res)))))
(testing "println appender works with with-out-str"
@@ -110,3 +110,11 @@
(is (= 3 (count (re-seq #"\"test warn\"" res)))))
(testing "lists are printed readably"
(is (= 2 (count (re-seq #"\(\\a \\b\)" res)))))))
+
+(deftest timbre-log!-test
+ (is (str/includes? (tu/bb nil
+ (pr-str '(do (require '[taoensso.timbre :as timbre])
+ (defn log-wrapper [& args]
+ (timbre/log! :info :p args))
+ (log-wrapper "hallo"))))
+ "hallo")))
diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj
index 28102ba8..b6e62947 100644
--- a/test/babashka/main_test.clj
+++ b/test/babashka/main_test.clj
@@ -1,6 +1,7 @@
(ns babashka.main-test
{:clj-kondo/config '{:linters {:unresolved-symbol {:exclude [working?]}}}}
(:require
+ [babashka.fs :as fs]
[babashka.main :as main]
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
@@ -9,6 +10,7 @@
[clojure.string :as str]
[clojure.test :as test :refer [deftest is testing]]
[flatland.ordered.map :refer [ordered-map]]
+ [flatland.ordered.set :refer [ordered-set]]
[sci.core :as sci]))
(defn bb [input & args]
@@ -31,11 +33,11 @@
(parse-opts ["--nrepl-server" "-cp" "src"])))
(is (= {:nrepl "1667", :classpath "src"}
(parse-opts ["-cp" "src" "nrepl-server"])))
- (is (= {:socket-repl "1666", :expressions ["123"]}
+ (is (= {:prn true :socket-repl "1666", :expressions ["123"]}
(parse-opts ["--socket-repl" "-e" "123"])))
- (is (= {:socket-repl "1666", :expressions ["123"]}
+ (is (= {:prn true :socket-repl "1666", :expressions ["123"]}
(parse-opts ["--socket-repl" "1666" "-e" "123"])))
- (is (= {:nrepl "1666", :expressions ["123"]}
+ (is (= {:prn true :nrepl "1666", :expressions ["123"]}
(parse-opts ["--nrepl-server" "1666" "-e" "123"])))
(is (= {:classpath "src"
:uberjar "foo.jar"}
@@ -50,7 +52,7 @@
(is (= 123 (bb nil "-e" "(println 123)")))
(is (= 123 (bb nil "--eval" "(println 123)")))
(testing "distinguish automatically between expression or file name"
- (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb")))
+ (is (= {:result 8080} (bb nil "--prn" "test/babashka/scripts/tools.cli.bb")))
(is (thrown-with-msg? Exception #"does not exist" (bb nil "foo.clj")))
(is (thrown-with-msg? Exception #"does not exist" (bb nil "-help"))))
(is (= "1 2 3" (bb nil "-e" "(require '[clojure.string :as str1])" "-e" "(str1/join \" \" [1 2 3])")))
@@ -64,8 +66,16 @@
(is (= {:force? true :list-tasks true :command-line-args nil} (parse-opts ["--force" "tasks"])))
(is (= {:force? true :run "sometask" :command-line-args nil} (parse-opts ["--force" "run" "sometask"])))
(is (= {:force? true :repl true} (parse-opts ["--force" "repl"])))
- (is (= {:force? true :clojure true :command-line-args '("-M" "-r")}
- (parse-opts ["--force" "clojure" "-M" "-r"]))))
+ (is (= {:force? true :clojure true :command-line-args '("-M" "-r")}
+ (parse-opts ["--force" "clojure" "-M" "-r"])))
+ (testing "file opts parsing does not mess with :command-line-args"
+ (is (= {:prn true, :expressions ["(prn :foo)"]}
+ (-> (let [[_ opts] (main/parse-file-opt ["-e" "(prn :foo)"] {})]
+ (main/parse-opts ["-e" "(prn :foo)"] opts)))))
+ (is (= {:file "foo", :command-line-args ["README.md"]}
+ (main/parse-opts ["README.md"] {:file "foo"})))
+ (is (= ["--version"] (bb nil (fs/file "test-resources" "script_with_overlapping_opts.clj") "--version")))
+ (is (= ["version"] (bb nil (fs/file "test-resources" "script_with_overlapping_opts.clj") "version")))))
(deftest version-test
(is (= [1 0 0] (main/parse-version "1.0.0-SNAPSHOT")))
@@ -138,7 +148,7 @@
(is (= "hello\n" (test-utils/bb nil "(println \"hello\")"))))
(deftest System-test
- (let [res (bb nil "-f" "test/babashka/scripts/System.bb")]
+ (let [res (bb nil "--prn" "-f" "test/babashka/scripts/System.bb")]
(is (= "bar" (second res)))
(doseq [s res]
(is (not-empty s)))))
@@ -147,7 +157,7 @@
(is (thrown-with-msg? Exception #"File does not exist: non-existing"
(bb nil "-f" "non-existing"))))
-(deftest ssl-test
+(deftest ^:flaky ssl-test
(let [resp (bb nil "(slurp \"https://www.google.com\")")]
(is (re-find #"doctype html" resp))))
@@ -202,31 +212,31 @@
(deftest init-test
(testing "init with a file"
- (is (= "foo" (bb nil "--init" "test-resources/babashka/init_test.clj"
- "-f" "test-resources/babashka/init_caller.clj"))))
+ (is (= "foo" (bb nil "--prn" "--init" "test-resources/babashka/init_test.clj"
+ "-f" "test-resources/babashka/init_caller.clj"))))
(testing "init with eval(s)"
(is (= "foo" (bb nil "--init" "test-resources/babashka/init_test.clj"
- "-e" "(init-test/do-a-thing)"))))
+ "-e" "(init-test/do-a-thing)"))))
(testing "init with main from init'ed ns"
- (is (= "Hello from init!" (bb nil "--init" "test-resources/babashka/init_test.clj"
- "-m" "init-test"))))
+ (is (= "Hello from init!" (bb nil "--prn" "--init" "test-resources/babashka/init_test.clj"
+ "-m" "init-test"))))
(testing "init with main from another namespace"
(test-utils/with-config '{:paths ["test-resources/babashka/src_for_classpath_test"]}
- (is (= "foo" (bb nil "--init" "test-resources/babashka/init_test.clj"
- "-m" "call-init-main")))))
+ (is (= "foo" (bb nil "--prn" "--init" "test-resources/babashka/init_test.clj"
+ "-m" "call-init-main")))))
(testing "init with a qualified function passed to --main"
(test-utils/with-config '{:paths ["test-resources/babashka/src_for_classpath_test"]}
- (is (= "foobar" (bb nil "--init" "test-resources/babashka/init_test.clj"
- "-m" "call-init-main/foobar")))))
+ (is (= "foobar" (bb nil "--prn" "--init" "test-resources/babashka/init_test.clj"
+ "-m" "call-init-main/foobar")))))
(testing "init with a subcommand after it"
(let [actual-output (test-utils/bb "(println (init-test/do-a-thing))"
- "--init" "test-resources/babashka/init_test.clj" "repl")]
+ "--init" "test-resources/babashka/init_test.clj" "repl")]
(is (str/includes? actual-output "foo\n")))
- (test-utils/with-config '{:tasks {thing (println (init-test/do-a-thing))}} ; make a task available
+ (test-utils/with-config '{:tasks {thing (println (init-test/do-a-thing))}} ; make a task available
(let [actual-output (test-utils/bb nil "--init" "test-resources/babashka/init_test.clj" "tasks")]
(is (every? #(str/includes? actual-output %) ["following tasks are available" "thing"])))))
(testing "init with a task name after it"
- (test-utils/with-config '{:tasks {thing (println (init-test/do-a-thing))}} ; make a task available
+ (test-utils/with-config '{:tasks {thing (println (init-test/do-a-thing))}} ; make a task available
(is (= "foo\n" (test-utils/bb nil "--init" "test-resources/babashka/init_test.clj" "thing"))))))
(deftest preloads-test
@@ -258,8 +268,8 @@
(deftest ^:windows-only win-pipe-test
(when (and test-utils/native? main/windows?)
(let [out (:out (sh "cmd" "/c" ".\\bb -O \"(repeat 50 \\\"dude\\\")\" |"
- ".\\bb --stream \"(str *input* \\\"rino\\\")\" |"
- ".\\bb -I \"(take 3 *input*)\""))
+ ".\\bb --stream \"(str *input* \\\"rino\\\")\" |"
+ ".\\bb -I \"(take 3 *input*)\""))
out (edn/read-string out)]
(is (= '("duderino" "duderino" "duderino") out)))))
@@ -303,7 +313,7 @@
(deftest create-temp-file-test
(is (= true
- (bb nil "(let [tfile (File/createTempFile \"ctf\" \"tmp\")]
+ (bb nil "(let [tfile (File/createTempFile \"ctf\" \"tmp\")]
(.deleteOnExit tfile) ; for cleanup
(.exists tfile))"))))
@@ -314,7 +324,7 @@
(is (= :timed-out (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777 {:default :timed-out :timeout 50})"))))
(let [edn (bb nil (io/file "test" "babashka" "scripts" "socket_server.bb"))]
(is (= "127.0.0.1" (:host edn)))
- (is (= 1777 (:port edn)))
+ (is (= 1777 (:port edn)))
(is (number? (:took edn)))))
(deftest ^:skip-windows wait-for-path-test
@@ -341,7 +351,7 @@
temp-dir-path))))))
(deftest tools-cli-test
- (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb"))))
+ (is (= {:result 8080} (bb nil "--prn" "test/babashka/scripts/tools.cli.bb"))))
(deftest try-catch-test
(is (zero? (bb nil "(try (/ 1 0) (catch ArithmeticException _ 0))")))
@@ -365,8 +375,8 @@
(deftest csv-test
(is (= '(["Adult" "87727"] ["Elderly" "43914"] ["Child" "33411"] ["Adolescent" "29849"]
- ["Infant" "15238"] ["Newborn" "10050"] ["In Utero" "1198"])
- (bb nil (.getPath (io/file "test" "babashka" "scripts" "csv.bb"))))))
+ ["Infant" "15238"] ["Newborn" "10050"] ["In Utero" "1198"])
+ (bb nil "--prn" (.getPath (io/file "test" "babashka" "scripts" "csv.bb"))))))
(deftest assert-test ;; assert was first implemented in bb but moved to sci later
(is (thrown-with-msg? Exception #"should-be-true"
@@ -389,14 +399,14 @@
(deftest binding-test
(is (= (if main/windows? 7 6)
- (bb nil "(def w (java.io.StringWriter.))
+ (bb nil "(def w (java.io.StringWriter.))
(binding [clojure.core/*out* w]
(println \"hello\"))
(count (str w))"))))
(deftest with-out-str-test
(is (= (if main/windows? 7 6)
- (bb nil "(count (with-out-str (println \"hello\")))"))))
+ (bb nil "(count (with-out-str (println \"hello\")))"))))
(deftest with-in-str-test
(is (= 5 (bb nil "(count (with-in-str \"hello\" (read-line)))"))))
@@ -419,7 +429,7 @@
(java.nio.file.Files/copy p p' (into-array [java.nio.file.StandardCopyOption/REPLACE_EXISTING]))))))"
temp-path))
(is (.exists f2))
- (let [v (bb nil "-f" (.getPath (io/file "test-resources" "babashka" "glob.clj")))]
+ (let [v (bb nil "--prn" "-f" (.getPath (io/file "test-resources" "babashka" "glob.clj")))]
(is (vector? v))
(is (.exists (io/file (first v)))))
(is (= :success (bb nil "(with-open [str (java.nio.file.Files/newDirectoryStream (.toPath (clojure.java.io/file \".\")))] :success)")))
@@ -432,7 +442,7 @@
(deftest future-print-test
(testing "the root binding of sci/*out*"
- (is (= "hello" (bb nil "@(future (prn \"hello\"))")))))
+ (is (= "hello" (bb nil "@(future (prn \"hello\"))")))))
(deftest Math-test
(is (== 8.0 (bb nil "(Math/pow 2 3)"))))
@@ -477,16 +487,52 @@
(deftest clojure-data-xml-test
(is (= "- 1
- 2
"
(bb nil "(let [xml (xml/parse-str \"- 1
- 2
\")] (xml/emit-str xml))")))
- (is (= "0.0.87-SNAPSHOT" (bb nil "examples/pom_version_get.clj" (.getPath (io/file "test-resources" "pom.xml")))))
+ (is (= "0.0.87-SNAPSHOT" (bb nil "--prn" "examples/pom_version_get.clj" (.getPath (io/file "test-resources" "pom.xml")))))
(is (= ":xmlns.DAV%3A/propfind"
(bb nil "(clojure.data.xml/alias-uri :D \"DAV:\") (str ::D/propfind)"))))
(deftest uberscript-test
(let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")]
(.deleteOnExit tmp-file)
+ (.delete tmp-file) ; prevent overwrite failure
(is (empty? (bb nil "--uberscript" (test-utils/escape-file-paths (.getPath tmp-file)) "-e" "(System/exit 1)")))
(is (= "(System/exit 1)" (slurp tmp-file)))))
+(deftest uberscript-overwrite-test
+ (testing "trying to make uberscript overwrite a non-jar file fails"
+ (let [tmp-file (java.io.File/createTempFile "uberscript_overwrite" ".clj")]
+ (.deleteOnExit tmp-file)
+ (is (thrown-with-msg? Exception #"Overwrite prohibited."
+ (test-utils/bb nil "--uberscript" (test-utils/escape-file-paths (.getPath tmp-file)) "-e" "(println 123)"))))))
+
+(deftest throw-on-empty-classpath
+ ;; this test fails the windows native test in CI
+ (when-not main/windows?
+ (testing "throw on empty classpath"
+ (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
+ path (.getPath tmp-file)]
+ (.deleteOnExit tmp-file)
+ (is (thrown-with-msg?
+ Exception #"classpath"
+ (test-utils/bb nil "uberjar" path "-m" "my.main-main")))))))
+
+(deftest target-file-overwrite-test
+ (test-utils/with-config {:paths ["test-resources/babashka/uberjar/src"]}
+ (testing "trying to make uberjar overwrite a non-empty jar file is allowed"
+ (let [tmp-file (java.io.File/createTempFile "uberjar_overwrite" ".jar")
+ path (.getPath tmp-file)]
+ (.deleteOnExit tmp-file)
+ (spit path "this isn't empty")
+ (test-utils/bb nil "--uberjar" (test-utils/escape-file-paths path) "-m" "my.main-main")
+ ; execute uberjar to confirm that the file is overwritten
+ (is (= "(\"42\")\n" (test-utils/bb nil "--prn" "--jar" (test-utils/escape-file-paths path) "42")))))
+ (testing "trying to make uberjar overwrite a non-jar file is not allowed"
+ (let [tmp-file (java.io.File/createTempFile "oops_all_source" ".clj")
+ path (.getPath tmp-file)]
+ (.deleteOnExit tmp-file)
+ (is (thrown-with-msg? Exception #"Overwrite prohibited."
+ (test-utils/bb nil "--uberjar" (test-utils/escape-file-paths path) "-m" "my.main-main")))))))
+
(deftest unrestricted-access
(testing "babashka is allowed to mess with built-in vars"
(is (= {} (bb nil "
@@ -587,7 +633,8 @@
(is (= 2 (bb nil "(set! *data-readers* {'t/tag inc}) #t/tag 1"))))
(deftest ordered-test
- (is (= (ordered-map :a 1 :b 2) (bb nil "(flatland.ordered.map/ordered-map :a 1 :b 2)"))))
+ (is (= (ordered-map :a 1 :b 2) (bb nil "(flatland.ordered.map/ordered-map :a 1 :b 2)")))
+ (is (= (ordered-set :a 1 :b 2) (bb nil "(flatland.ordered.set/ordered-set :a 1 :b 2)"))))
(deftest data-diff-test
(is (= [[nil 1] [nil 2] [1 nil 2]] (bb nil "(require '[clojure.data :as d]) (d/diff [1 1 2] [1 2 2])"))))
@@ -617,13 +664,13 @@
(deftest file-property-test
(is (= "true\nfalse\n"
- (test-utils/bb nil (.getPath (io/file "test-resources" "babashka" "file_property1.clj")))))
+ (test-utils/bb nil "--prn" (.getPath (io/file "test-resources" "babashka" "file_property1.clj")))))
(is (= "true\n"
- (test-utils/bb nil (.getPath (io/file "test-resources" "babashka" "file_property2.clj")))))
+ (test-utils/bb nil "--prn" (.getPath (io/file "test-resources" "babashka" "file_property2.clj")))))
(is (apply =
- (bb nil (.getPath (io/file "test" "babashka" "scripts" "simple_file_var.bb")))))
- (let [res (bb nil (.getPath (io/file "test" ".." "test" "babashka"
- "scripts" "simple_file_var.bb")))]
+ (bb nil "--prn" (.getPath (io/file "test" "babashka" "scripts" "simple_file_var.bb")))))
+ (let [res (bb nil "--prn" (.getPath (io/file "test" ".." "test" "babashka"
+ "scripts" "simple_file_var.bb")))]
(is (apply = res))
(is (str/includes? (first res) ".."))))
@@ -744,8 +791,8 @@ true")))
(deftest ^:windows-only win-process-handler-info-test
(when (and test-utils/native? main/windows?)
(is (str/ends-with?
- (bb nil "-e" "(.get (.command (.info (java.lang.ProcessHandle/current))))")
- "bb.exe"))))
+ (bb nil "-e" "(.get (.command (.info (java.lang.ProcessHandle/current))))")
+ "bb.exe"))))
(deftest interop-concurrency-test
(is (= ["true" 3] (last (bb nil "-e"
@@ -773,26 +820,26 @@ true")))
(is (<= 8 (bb nil '(count (apropos "first")))))
(is (= [1 2 3] (bb "[1 2 3]" "(pprint *input*)")))
(let [first-doc (test-utils/bb nil "(doc first)")]
- (is (every? #(str/includes? first-doc %) ["---" "clojure.core/first" "first item"])))))
+ (is (every? #(str/includes? first-doc %) ["---" "clojure.core/first" "first item"])))))
(deftest edn-input-test
(testing "clojure's default readers"
(is (= '(#inst "2021-08-24T00:56:02.014-00:00")
- (bb "#inst \"2021-08-24T00:56:02.014-00:00\"" "-I" "(println *input*)")))
+ (bb "#inst \"2021-08-24T00:56:02.014-00:00\"" "-I" "(println *input*)")))
(is (= '(#uuid "00000000-0000-0000-0000-000000000000")
- (bb "#uuid \"00000000-0000-0000-0000-000000000000\"" "-I" "(println *input*)"))))
+ (bb "#uuid \"00000000-0000-0000-0000-000000000000\"" "-I" "(println *input*)"))))
(testing "use tagged-literal as default data reader fn..."
(testing "when using the -I option"
(is (= "(#made-up-tag 42)\n"
- (test-utils/normalize (test-utils/bb "#made-up-tag 42" "-I" "(println *input*)"))))
+ (test-utils/normalize (test-utils/bb "#made-up-tag 42" "-I" "(println *input*)"))))
(is (= "(#abc 123 #cde 789)\n"
- (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "-I" "(map :a *input*)")))))
+ (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "-I" "(map :a *input*)")))))
(testing "when using --stream and -I"
(is (= "#abc 123\n#cde 789\n"
- (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "--stream" "-I" "-e" "(println (:a *input*))")))))
+ (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "--stream" "-I" "-e" "(println (:a *input*))")))))
(testing "when using --stream (-I is sort of implied if no -i)"
(is (= "#abc 123\n#cde 789\n"
- (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "--stream" "-e" "(println (:a *input*))")))))
+ (test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "--stream" "-e" "(println (:a *input*))")))))
(testing "when reading one EDN form from stdin (no --stream or -I or -i)"
(is (= "#abc 123\n"
(test-utils/normalize (test-utils/bb "{:a #abc 123}{:a #cde 789}" "-e" "(println (:a *input*))")))))))
@@ -843,6 +890,17 @@ true")))
(deftest index-of-test
(is (= 1 (bb nil "(.indexOf (map inc [1 2 3]) 3)"))))
+(deftest get-watches-test
+ (is (true? (bb nil "(map? (.getWatches (doto (atom nil) (add-watch :foo (fn [k r o n])))))"))))
+
+(deftest tools-reader-test
+ (is (= :user/foo (bb nil "(require '[clojure.tools.reader :as r]) (r/read-string \"::foo\")")))
+ (is (= :clojure.tools.reader/foo (bb nil "(require '[clojure.tools.reader :as r]) (r/read-string \"::r/foo\")")))
+ (is (= [1 2 3] (bb nil "
+(require '[clojure.tools.reader :as r])
+(binding [r/*default-data-reader-fn* (fn [sym] (fn [val] [1 2 3]))]
+(r/read-string \"#dude []\"))"))))
+
;;;; Scratch
(comment
diff --git a/test/babashka/namespace_test.clj b/test/babashka/namespace_test.clj
index 7d8b1f5b..1e825b24 100644
--- a/test/babashka/namespace_test.clj
+++ b/test/babashka/namespace_test.clj
@@ -23,3 +23,9 @@
{:containing-ns ns-ns-name
:ns-on-var var-ns-name
:var-name var-symbol}))")))))
+
+(deftest reload-existing-ns-test
+ (is (bb nil "(require '[clojure.java.io] :reload) true")))
+
+(deftest file-not-found-exception-non-existing-ns-test
+ (is (= :user/dude (bb nil "(try (require '[foo-dude.bar]) (catch java.io.FileNotFoundException _ ::dude))"))))
diff --git a/test/babashka/print_deps_test.clj b/test/babashka/print_deps_test.clj
index 4d06b0d5..7471875e 100644
--- a/test/babashka/print_deps_test.clj
+++ b/test/babashka/print_deps_test.clj
@@ -2,16 +2,28 @@
(:require [babashka.deps :as deps]
[babashka.fs :as fs]
[babashka.test-utils :refer [bb]]
+ [borkdude.rewrite-edn :as r]
[clojure.string :as str]
[clojure.test :refer [deftest is testing]]
+ [rewrite-clj.node :as n]
[sci.core :as sci]))
+
(deftest print-deps-test
- (let [deps (bb nil "print-deps" "--format" "deps")
- tmp-dir (fs/create-temp-dir)]
+ (let [deps (bb nil "print-deps" "--format" "deps")]
(testing "printed deps map can be read by Clojure"
- (spit (fs/file tmp-dir "deps.edn") deps)
- (let [cp (sci/with-out-str
- (deps/clojure ["-Spath"] {:dir (str tmp-dir)}))]
- (is (str/includes? cp "babashka.curl")))
- (fs/delete-tree tmp-dir))))
+ (let [tmp-dir (fs/create-temp-dir)]
+ (spit (fs/file tmp-dir "deps.edn") deps)
+ (let [cp (sci/with-out-str
+ (deps/clojure ["-Spath"] {:dir (str tmp-dir)}))]
+ (is (str/includes? cp "babashka.curl")))
+ (fs/delete-tree tmp-dir)))
+
+ (testing "keys in dep map are sorted"
+ (let [values-sorted? (fn [xs] (= xs (sort xs)))
+ deps-edn-str-deps-keys (fn [s]
+ (->> (r/get (r/parse-string s) :deps)
+ n/child-sexprs
+ (partition 2)
+ (map first)))]
+ (is (values-sorted? (deps-edn-str-deps-keys deps)))))))
diff --git a/test/babashka/sci_test.clj b/test/babashka/sci_test.clj
new file mode 100644
index 00000000..477fe493
--- /dev/null
+++ b/test/babashka/sci_test.clj
@@ -0,0 +1,14 @@
+(ns babashka.sci-test
+ (:require
+ [babashka.test-utils :as tu]
+ [clojure.edn :as edn]
+ [clojure.test :as t :refer [deftest is]]))
+
+(deftest sci-test
+ (is (= 1 (edn/read-string
+ (tu/bb nil "-e" "
+(ns foo)
+(require '[sci.core :as sci])
+(def x 1)
+(def ctx (sci/init {:namespaces {'foo (sci/copy-ns foo (sci/create-ns 'foo))}}))
+(sci/eval-string* ctx \"foo/x\")")))))
diff --git a/test/babashka/test_test.clj b/test/babashka/test_test.clj
index b0ad6da5..0f4c6cdc 100644
--- a/test/babashka/test_test.clj
+++ b/test/babashka/test_test.clj
@@ -37,8 +37,12 @@
(deftest fixtures-test
(let [output (bb "
(require '[clojure.test :as t])
-(defn once [f] (prn :once-before) (f) (prn :once-after))
-(defn each [f] (prn :each-before) (f) (prn :each-after))
+(defn once [f] (prn :once-before) (f)
+(prn :once-after)
+(prn (some? (::t/once-fixtures (meta *ns*)))))
+
+(defn each [f] (prn :each-before) (f) (prn :each-after)
+(prn (some? (::t/each-fixtures (meta *ns*)))))
(t/use-fixtures :once once)
(t/use-fixtures :each each)
(t/deftest foo)
@@ -48,9 +52,12 @@
:once-before
:each-before
:each-after
+true
:each-before
:each-after
-:once-after")))))
+true
+:once-after
+true")))))
(deftest with-test
(let [output (bb "
diff --git a/test/babashka/test_utils.clj b/test/babashka/test_utils.clj
index 9a856a96..b2b440eb 100644
--- a/test/babashka/test_utils.clj
+++ b/test/babashka/test_utils.clj
@@ -5,7 +5,6 @@
[babashka.impl.common :as common]
[babashka.main :as main]
[babashka.process :as p]
- [clojure.edn :as edn]
[clojure.string :as str]
[clojure.test :as test :refer [*report-counters*]]
[clojure.tools.reader.reader-types :as r]
@@ -45,7 +44,7 @@
(System/exit 1)))))
(defn bb-jvm [input-or-opts & args]
- (reset! cp/cp-state nil)
+ (alter-var-root #'cp/the-url-loader (constantly (delay (cp/new-loader []))))
(reset! main/env {})
(vreset! common/bb-edn nil)
(System/clearProperty "babashka.config")
diff --git a/test/babashka/uberjar_test.clj b/test/babashka/uberjar_test.clj
index 4476f45a..c8ad8c21 100644
--- a/test/babashka/uberjar_test.clj
+++ b/test/babashka/uberjar_test.clj
@@ -2,8 +2,10 @@
(:require
[babashka.fs :as fs]
[babashka.main :as main]
+ [babashka.process :refer [shell]]
[babashka.test-utils :as tu]
[clojure.edn :as edn]
+ [clojure.java.io :as io]
[clojure.string :as str]
[clojure.test :as t :refer [deftest is testing]])
(:import (java.io File InputStreamReader PushbackReader)
@@ -77,15 +79,16 @@
InputStreamReader. PushbackReader. edn/read)]
(is (= #{:pods} (-> bb-edn keys set)))
(is (= (:pods config) (:pods bb-edn))))
- (is (str/includes? (tu/bb nil "--jar" path) "3")))))))
+ (is (str/includes? (tu/bb nil "--prn" "--jar" path) "3")))))))
-(deftest throw-on-empty-classpath
- ;; this test fails the windows native test in CI
- (when-not main/windows?
- (testing "throw on empty classpath"
- (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
- path (.getPath tmp-file)]
- (.deleteOnExit tmp-file)
- (is (thrown-with-msg?
- Exception #"classpath"
- (tu/bb nil "uberjar" path "-m" "my.main-main")))))))
+(deftest uberjar-as-binary-test
+ (when tu/native?
+ (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
+ path (.getPath tmp-file)
+ bin-file (if (fs/windows?) "my-binary.exe" "my-binary")]
+ (.deleteOnExit tmp-file)
+ (.deleteOnExit (io/file bin-file))
+ (tu/bb nil "--classpath" "test-resources/babashka/uberjar/src" "uberjar" path "-m" "my.main-main")
+ (shell {:out bin-file} "cat" "./bb" path)
+ (.setExecutable (io/file bin-file) true)
+ (is (str/includes? (:out (shell {:out :string} (str (io/file "." bin-file)) "1 2 3 4")) "1 2 3 4")))))
diff --git a/test/babashka/uberscript_test.clj b/test/babashka/uberscript_test.clj
index 9a111b18..66376038 100644
--- a/test/babashka/uberscript_test.clj
+++ b/test/babashka/uberscript_test.clj
@@ -1,35 +1,37 @@
(ns babashka.uberscript-test
(:require
[babashka.test-utils :as tu]
- [clojure.test :as t :refer [deftest is]]
- [clojure.string :as str]))
+ [clojure.string :as str]
+ [clojure.test :as t :refer [deftest is]]))
+
+(defn deleted-temp-file []
+ (doto (java.io.File/createTempFile "uberscript" ".clj")
+ .deleteOnExit
+ .delete)) ; delete file to prevent overwrite failure
(deftest basic-test
- (let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")]
- (.deleteOnExit tmp-file)
- (is (empty? (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test" "uberscript" (.getPath tmp-file) "-m" "my.main")))
+ (let [tmp-file (deleted-temp-file)]
+ (is (empty? (tu/bb nil "--prn" "--classpath" "test-resources/babashka/src_for_classpath_test" "uberscript" (.getPath tmp-file) "-m" "my.main")))
(is (= "(\"1\" \"2\" \"3\" \"4\")\n"
- (tu/bb nil "--file" (.getPath tmp-file) "1" "2" "3" "4")))))
+ (tu/bb nil "--prn" "--file" (.getPath tmp-file) "1" "2" "3" "4")))))
(when-not (= "aarch64" (System/getenv "BABASHKA_ARCH"))
(deftest advanced-test
- (let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")]
- (.deleteOnExit tmp-file)
+ (let [tmp-file (deleted-temp-file)]
;; we test:
;; order of namespaces
;; reader error for ::a/foo is swallowed
;; pod namespaces can be loaded without a problem
;; resulting program can be executed
- (is (empty? (tu/bb nil "--classpath" "test-resources/babashka/uberscript/src" "uberscript" (.getPath tmp-file) "-m" "my.main")))
+ (is (empty? (tu/bb nil "--prn" "--classpath" "test-resources/babashka/uberscript/src" "uberscript" (.getPath tmp-file) "-m" "my.main")))
(is (= ":clojure.string/foo\ntrue\n(\"1\" \"2\" \"3\" \"4\")\n"
- (tu/bb nil "--file" (.getPath tmp-file) "1" "2" "3" "4"))))))
+ (tu/bb nil "--prn" "--file" (.getPath tmp-file) "1" "2" "3" "4"))))))
(deftest pods-test
- (let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")]
- (.deleteOnExit tmp-file)
+ (let [tmp-file (deleted-temp-file)]
(tu/with-config (pr-str '{:paths ["test-resources/babashka/uberscript/src"]
:pods {org.babashka/go-sqlite3 {:version "0.1.0"}}})
- (is (empty? (tu/bb nil "uberscript" (.getPath tmp-file) "-m" "my.main-pod")))
+ (is (empty? (tu/bb nil "--prn" "uberscript" (.getPath tmp-file) "-m" "my.main-pod")))
(is (= 1 (count (re-seq #"load-pod 'org.babashka/go-sqlite3"
(str/join (str/split-lines (slurp tmp-file))))))))
- (is (str/includes? (tu/bb nil "--file" (.getPath tmp-file)) "3"))))
+ (is (str/includes? (tu/bb nil "--prn" "--file" (.getPath tmp-file)) "3"))))
diff --git a/test/babashka/xml_test.clj b/test/babashka/xml_test.clj
index b3fde386..7624688d 100644
--- a/test/babashka/xml_test.clj
+++ b/test/babashka/xml_test.clj
@@ -1,7 +1,7 @@
(ns babashka.xml-test
(:require [babashka.test-utils :as test-utils]
[clojure.string :as str]
- [clojure.test :refer [deftest is testing]]))
+ [clojure.test :refer [deftest is]]))
(def simple-xml-str "data")
@@ -15,3 +15,22 @@
(deftest xml-data-readers-test
(is (str/includes? (test-utils/bb nil round-trip-prog) simple-xml-str)))
+
+(deftest virtual-threads-bug-test
+ (is (str/starts-with? (test-utils/bb nil "(require '[clojure.core.async]
+ '[clojure.data.xml])
+
+(def go-blocks (atom []))
+
+(dotimes [_ 100]
+ (swap! go-blocks conj (clojure.core.async/go (clojure.data.xml/parse
+ (java.io.ByteArrayInputStream.
+ (.getBytes \"\" \"UTF-8\"))
+ :namespace-aware false
+ :skip-whitespace true))))
+
+(doseq [block @go-blocks]
+ (clojure.core.async/