diff --git a/.circleci/config.yml b/.circleci/config.yml
index ad653a42..53356bc5 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -76,7 +76,7 @@ jobs:
working_directory: ~/repo
environment:
LEIN_ROOT: "true"
- GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.0.0
+ GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.1.0
BABASHKA_PLATFORM: linux # used in release script
BABASHKA_TEST_ENV: native
BABASHKA_XMX: "-J-Xmx6500m"
@@ -110,9 +110,9 @@ jobs:
name: Download GraalVM
command: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
fi
- run:
name: Build binary
@@ -136,7 +136,7 @@ jobs:
- save_cache:
paths:
- ~/.m2
- - ~/graalvm-ce-java11-21.0.0
+ - ~/graalvm-ce-java11-21.1.0
key: linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- store_artifacts:
path: /tmp/release
@@ -151,7 +151,7 @@ jobs:
working_directory: ~/repo
environment:
LEIN_ROOT: "true"
- GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.0.0
+ GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.1.0
BABASHKA_PLATFORM: linux # used in release script
BABASHKA_TEST_ENV: native
BABASHKA_STATIC: "true"
@@ -198,9 +198,9 @@ jobs:
name: Download GraalVM
command: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
fi
- run:
name: Build binary
@@ -224,7 +224,7 @@ jobs:
- save_cache:
paths:
- ~/.m2
- - ~/graalvm-ce-java11-21.0.0
+ - ~/graalvm-ce-java11-21.1.0
key: linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- store_artifacts:
path: /tmp/release
@@ -241,7 +241,7 @@ jobs:
working_directory: ~/repo
environment:
LEIN_ROOT: "true"
- GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.0.0
+ GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.1.0
BABASHKA_PLATFORM: linux # used in release script
BABASHKA_ARCH: aarch64
BABASHKA_TEST_ENV: native
@@ -287,9 +287,9 @@ jobs:
name: Download GraalVM
command: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-aarch64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-aarch64-21.1.0.tar.gz
fi
- run:
name: Build binary
@@ -313,7 +313,7 @@ jobs:
- save_cache:
paths:
- ~/.m2
- - ~/graalvm-ce-java11-21.0.0
+ - ~/graalvm-ce-java11-21.1.0
key: linux-aarch64-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- store_artifacts:
path: /tmp/release
@@ -330,7 +330,7 @@ jobs:
working_directory: ~/repo
environment:
LEIN_ROOT: "true"
- GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.0.0
+ GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.1.0
BABASHKA_PLATFORM: linux # used in release script
BABASHKA_ARCH: aarch64
BABASHKA_TEST_ENV: native
@@ -378,9 +378,9 @@ jobs:
name: Download GraalVM
command: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-aarch64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-aarch64-21.1.0.tar.gz
fi
- run:
name: Build binary
@@ -404,7 +404,7 @@ jobs:
- save_cache:
paths:
- ~/.m2
- - ~/graalvm-ce-java11-21.0.0
+ - ~/graalvm-ce-java11-21.1.0
key: linux-aarch64-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- store_artifacts:
path: /tmp/release
@@ -418,7 +418,7 @@ jobs:
xcode: "12.0.0"
environment:
MACOSX_DEPLOYMENT_TARGET: 10.13 # 10.12 is EOL
- GRAALVM_HOME: /Users/distiller/graalvm-ce-java11-21.0.0/Contents/Home
+ GRAALVM_HOME: /Users/distiller/graalvm-ce-java11-21.1.0/Contents/Home
BABASHKA_PLATFORM: macos # used in release script
BABASHKA_TEST_ENV: native
BABASHKA_XMX: "-J-Xmx6500m"
@@ -446,9 +446,9 @@ jobs:
command: |
cd ~
ls -la
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-darwin-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-darwin-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-darwin-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-darwin-amd64-21.1.0.tar.gz
fi
- run:
name: Build binary
@@ -470,7 +470,7 @@ jobs:
- save_cache:
paths:
- ~/.m2
- - ~/graalvm-ce-java11-21.0.0
+ - ~/graalvm-ce-java11-21.1.0
key: mac-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- store_artifacts:
path: /tmp/release
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 52cef161..c93c1ac4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -45,17 +45,17 @@ jobs:
uses: actions/cache@v1
id: cache-graalvm
with:
- path: ~/graalvm-ce-java11-21.0.0
- key: ${{ runner.os }}-graalvm-21.0.0
+ path: ~/graalvm-ce-java11-21.1.0
+ key: ${{ runner.os }}-graalvm-21.1.0
restore-keys: |
- ${{ runner.os }}-graalvm-21.0.0
+ ${{ runner.os }}-graalvm-21.1.0
- name: Download GraalVM
run: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
fi
- name: Fetch deps
@@ -65,18 +65,18 @@ jobs:
- name: Run tests
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
script/test
- name: Test libraries
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
sudo script/install-clojure
script/run_lib_tests
- name: Build uberjar
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
script/uberjar
- name: Babashka version
@@ -133,17 +133,17 @@ jobs:
uses: actions/cache@v1
id: cache-graalvm
with:
- path: ~/graalvm-ce-java11-21.0.0
- key: ${{ runner.os }}-graalvm-21.0.0
+ path: ~/graalvm-ce-java11-21.1.0
+ key: ${{ runner.os }}-graalvm-21.1.0
restore-keys: |
- ${{ runner.os }}-graalvm-21.0.0
+ ${{ runner.os }}-graalvm-21.1.0
- name: Download GraalVM
run: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
fi
- name: Babashka version
@@ -156,13 +156,13 @@ jobs:
run: |
export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar
export BABASHKA_XMX="-J-Xmx6g"
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json
script/compile
- name: Test binary
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
BABASHKA_TEST_ENV=native script/test
- name: Install clojure
@@ -171,7 +171,7 @@ jobs:
- name: Test libraries
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
BABASHKA_TEST_ENV=native script/run_lib_tests
- name: Upload artifact
@@ -214,17 +214,17 @@ jobs:
uses: actions/cache@v1
id: cache-graalvm
with:
- path: ~/graalvm-ce-java11-21.0.0
- key: ${{ runner.os }}-graalvm-21.0.0
+ path: ~/graalvm-ce-java11-21.1.0
+ key: ${{ runner.os }}-graalvm-21.1.0
restore-keys: |
- ${{ runner.os }}-graalvm-21.0.0
+ ${{ runner.os }}-graalvm-21.1.0
- name: Download GraalVM
run: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
fi
- name: Babashka version
@@ -237,7 +237,7 @@ jobs:
run: |
export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar
export BABASHKA_XMX="-J-Xmx6g"
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
export BABASHKA_STATIC=true
cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json
script/compile
@@ -245,7 +245,7 @@ jobs:
- name: Test binary
run: |
./bb '(+ 1 2 3)'
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
BABASHKA_TEST_ENV=native script/test
- name: Install clojure
@@ -254,7 +254,7 @@ jobs:
- name: Test libraries
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0"
BABASHKA_TEST_ENV=native script/run_lib_tests
- name: Upload artifact
@@ -288,17 +288,17 @@ jobs:
uses: actions/cache@v1
id: cache-graalvm
with:
- path: ~/graalvm-ce-java11-21.0.0
- key: ${{ runner.os }}-graalvm-21.0.0
+ path: ~/graalvm-ce-java11-21.1.0
+ key: ${{ runner.os }}-graalvm-21.1.0
restore-keys: |
- ${{ runner.os }}-graalvm-21.0.0
+ ${{ runner.os }}-graalvm-21.1.0
- name: Download GraalVM
run: |
cd ~
- if ! [ -d graalvm-ce-java11-21.0.0 ]; then
- curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-darwin-amd64-21.0.0.tar.gz
- tar xzf graalvm-ce-java11-darwin-amd64-21.0.0.tar.gz
+ if ! [ -d graalvm-ce-java11-21.1.0 ]; then
+ curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-darwin-amd64-21.1.0.tar.gz
+ tar xzf graalvm-ce-java11-darwin-amd64-21.1.0.tar.gz
fi
- name: Babashka version
@@ -311,19 +311,19 @@ jobs:
run: |
export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar
export BABASHKA_XMX="-J-Xmx6g"
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0/Contents/Home"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0/Contents/Home"
cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json
script/compile
- name: Test binary
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0/Contents/Home"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0/Contents/Home"
sudo script/install-leiningen
BABASHKA_TEST_ENV=native script/test
- name: Test libraries
run: |
- export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.0.0/Contents/Home"
+ export GRAALVM_HOME="$HOME/graalvm-ce-java11-21.1.0/Contents/Home"
sudo script/install-clojure
BABASHKA_TEST_ENV=native script/run_lib_tests
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37945b19..0a5bcf6b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,44 @@
For a list of breaking changes, check [here](#breaking-changes).
+## 0.4.6
+
+- Upgrade to GraalVM 21.1, fixes [#884](https://github.com/babashka/babashka/issues/884)
+
+## 0.4.5
+
+Babashka proper:
+
+- Add `java.net.InetSocketAddress`
+- Add support for slingshot [#675](https://github.com/babashka/babashka/issues/675)
+- Add STM facilities (`dosync`, `ref`, etc.)
+- Fix `.wait`, `.notify` interop on arbitrary classes
+
+Deps.clj (used for resolving deps and `clojure` invocations):
+
+- Fix JVM option parsing [#46](https://github.com/borkdude/deps.clj/issues/46)
+
+Sci: various minor performance improvements.
+
+## 0.4.4
+
+Babashka proper:
+
+- Print ex-data in error report [#730](https://github.com/babashka/babashka/issues/730) ([@GreshamDanielStephens](https://github.com/GreshamDanielStephens), [@rng-dynamics](https://github.com/rng-dynamics))
+- Tasks: support dynamic vars [#865](https://github.com/babashka/babashka/issues/865)
+- Tasks: use stable namespace when using `run` [#865](https://github.com/babashka/babashka/issues/865)
+- Add `java.lang.ProcessHandle$Info` [#872](https://github.com/babashka/babashka/issues/872)
+- Add `java.util.Optional` [#872](https://github.com/babashka/babashka/issues/872)
+- Add `java.lang.StackTraceElement` (to gain compatibility with libraries such as [omniconf](https://github.com/grammarly/omniconf))
+
+Babashka.nrepl:
+
+- Error reporting improvement [#40](https://github.com/babashka/babashka.nrepl/issues/865)
+
+Sci:
+
+- Support trailing metadata in `defn`
+
## 0.4.3
- Add `cognitect.transit/tagged-value`, needed for sql pods
diff --git a/Dockerfile b/Dockerfile
index ba680a5a..a56bbafc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,13 +4,13 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt update
RUN apt install --no-install-recommends -yy curl unzip build-essential zlib1g-dev sudo
WORKDIR "/opt"
-RUN curl -sLO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
-RUN tar -xzf graalvm-ce-java11-linux-amd64-21.0.0.tar.gz
+RUN curl -sLO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
+RUN tar -xzf graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
ARG BABASHKA_XMX="-J-Xmx4500m"
-ENV GRAALVM_HOME="/opt/graalvm-ce-java11-21.0.0"
-ENV JAVA_HOME="/opt/graalvm-ce-java11-21.0.0/bin"
+ENV GRAALVM_HOME="/opt/graalvm-ce-java11-21.1.0"
+ENV JAVA_HOME="/opt/graalvm-ce-java11-21.1.0/bin"
ENV PATH="$JAVA_HOME:$PATH"
ENV BABASHKA_XMX=$BABASHKA_XMX
diff --git a/appveyor.yml b/appveyor.yml
index 3fb7e31e..b5e535ed 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,7 +7,8 @@ image: Visual Studio 2017
clone_folder: C:\projects\babashka
environment:
- GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-ce-java11-21.0.0
+ GRAALVM_HOME: C:\projects\babashka\graalvm\graalvm-ce-java11-21.1.0
+ JAVA_HOME: C:\projects\babashka\graalvm\graalvm-ce-java11-21.1.0
BABASHKA_XMX: "-J-Xmx5g"
cache:
@@ -30,24 +31,26 @@ clone_script:
- cmd: git submodule update --init --recursive
build_script:
+- cmd: >-
+ powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-windows-amd64-21.1.0.zip', 'graalvm.zip') }"
+
+ powershell -Command "if (Test-Path('graalvm')) { return } else { Expand-Archive graalvm.zip graalvm }"
+
- cmd: >-
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat', 'lein.bat')"
call lein self-install
-# set CLJ_KONDO_TEST_ENV=jvm
+- cmd: >-
+ set BABASHKA_TEST_ENV=jvm
-# call script/test.bat
+ call script/test.bat
# see https://github.com/quarkusio/quarkus/pull/7663
- cmd: >-
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
- powershell -Command "if (Test-Path('graalvm')) { return } else { (New-Object Net.WebClient).DownloadFile('https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-windows-amd64-21.0.0.zip', 'graalvm.zip') }"
-
- powershell -Command "if (Test-Path('graalvm')) { return } else { Expand-Archive graalvm.zip graalvm }"
-
call script/uberjar.bat
call script/compile.bat
@@ -62,12 +65,9 @@ build_script:
bb release-artifact %zip%
-# - cmd: >-
-# lein clean
+ set BABASHKA_TEST_ENV=native
-# set CLJ_KONDO_TEST_ENV=native
-
-# call script/test.bat
+ call script/test.bat
artifacts:
- path: babashka-*-windows-amd64.zip
diff --git a/babashka.nrepl b/babashka.nrepl
index d9b63bba..bd1ce0cb 160000
--- a/babashka.nrepl
+++ b/babashka.nrepl
@@ -1 +1 @@
-Subproject commit d9b63bbadce04799ef791c02a7066dd3197aa1b9
+Subproject commit bd1ce0cbc0861350a4a36e9c31ef79fa0c7cff84
diff --git a/deps.clj b/deps.clj
index f59e735a..520b6b05 160000
--- a/deps.clj
+++ b/deps.clj
@@ -1 +1 @@
-Subproject commit f59e735a585d73e9f800a7e824e2afa550092caf
+Subproject commit 520b6b053b7bdfe46990ab82220a2d13f79f9772
diff --git a/deps.edn b/deps.edn
index 6d3bca04..ec064874 100644
--- a/deps.edn
+++ b/deps.edn
@@ -78,7 +78,8 @@
gaka/gaka {:mvn/version "0.3.0"}
failjure/failjure {:mvn/version "2.1.1"}
io.helins/binf {:mvn/version "1.1.0-beta0"}
- rm-hull/jasentaa {:mvn/version "0.2.5"}}
+ rm-hull/jasentaa {:mvn/version "0.2.5"}
+ slingshot/slingshot {:mvn/version "0.12.2"}}
:classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil
org.clojure/core.specs.alpha nil}}
diff --git a/doc/build.md b/doc/build.md
index 78a2da8f..c27082d5 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-21.0.0*.
+- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *java11-21.1.0*.
- 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-21.0.0/Contents/Home
+ export GRAALVM_HOME=~/Downloads/graalvm-ce-java11-21.1.0/Contents/Home
```
On linux:
``` shell
- export GRAALVM_HOME=~/Downloads/graalvm-ce-java11-21.0.0
+ export GRAALVM_HOME=~/Downloads/graalvm-ce-java11-21.1.0
```
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-21.0.0
+ set GRAALVM_HOME=%USERPROFILE%\Downloads\graalvm-ce-java11-21.1.0
```
If you are not running from the x64 Native Tools Command Prompt, you will need to set additional environment variables using:
```
diff --git a/doc/dev.md b/doc/dev.md
index 1c5f3c6b..d9e4e15c 100644
--- a/doc/dev.md
+++ b/doc/dev.md
@@ -1,6 +1,6 @@
# Developing Babashka
-You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java11-21.0.0.
+You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java11-21.1.0.
## Clone repository
@@ -114,6 +114,8 @@ Some of these design decisions were formed in [these discussions](https://github
Keep notes here about how adding libraries and classes to Babashka affects the binary size.
We're registering the size of the macOS binary (as built on CircleCI).
+2021/06/13 Upgrading from GraalvM 21.0 to 21.1 added roughly 3mb. Issue [here](https://github.com/oracle/graal/issues/3280#issuecomment-846402115).
+
2020/10/30 Without httpkit client+server: 68113436. With: 69503316 = 1390kb added.
2020/05/01 Removed `next.jdbc` and postgres JDBC driver: 48304980
diff --git a/doc/projects.md b/doc/projects.md
index 4194eef8..41737362 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -39,6 +39,7 @@ The following libraries and projects are known to work with babashka.
- [binf](#binf)
- [rewrite-edn](#rewrite-edn)
- [expound](#expound)
+ - [omniconf](#omniconf)
- [Pods](#pods)
- [Projects](#projects-1)
- [babashka-test-action](#babashka-test-action)
@@ -60,6 +61,7 @@ The following libraries and projects are known to work with babashka.
- [interdep](#interdep)
- [sha-words](#sha-words)
- [adam-james-v/scripts](#adam-james-vscripts)
+ - [oidc-client](#oidc-client)
Also keep an eye on the [news](news.md) page for new projects, gists and other
developments around babashka.
@@ -544,6 +546,44 @@ Example:
(expound/expound ::a [1 2])
```
+### [omniconf](https://github.com/grammarly/omniconf)
+
+script.clj:
+``` clojure
+#!/usr/bin/env bb
+
+(ns script
+ (:require [babashka.deps :as deps]))
+
+(deps/add-deps
+ '{:deps {com.grammarly/omniconf {:mvn/version "0.4.3"}}})
+
+(require '[omniconf.core :as cfg])
+(cfg/define {:foo {}})
+(cfg/populate-from-env)
+(cfg/get :foo)
+```
+
+``` text
+FOO=1 script.clj
+Populating Omniconf from env: 1 value(s)
+"1"
+```
+
+### [slingshot](https://github.com/scgilardi/slingshot)
+
+Enhanced try and throw for Clojure leveraging Clojure's capabilities.
+
+``` clojure
+$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {slingshot/slingshot {:mvn/version "0.12.2"}}}')
+$ bb -e "(require '[slingshot.slingshot :as s]) (s/try+ (s/throw+ {:type ::foo}) (catch [:type ::foo] [] 1))"
+1
+```
+
+NOTE: slingshot's tests pass with babashka except one: catching a record types
+by name. This is due to a difference in how records are implemented in
+babashka. This may be fixed later if this turns out to be really useful.
+
## Pods
[Babashka pods](https://github.com/babashka/babashka.pods) are programs that can
@@ -649,3 +689,9 @@ A clojure program to turn a sha hash into list of nouns in a predictable jar.
### [adam-james-v/scripts](https://github.com/adam-james-v/scripts)
A collection of useful scripts. Mainly written with Clojure/babashka
+
+### [oidc-client](https://gist.github.com/holyjak/ad4e1e9b863f8ed57ef0cb6ac6b30494)
+
+Tired of being forced to use the browser every time you need to refresh an OIDC token to authenticate with a backend service? Finally there is a CLI tool for that - the babashka and Docker powered oidc_client.clj.
+
+Upon first invocation it opens up a browser for the OIDC provider login, thereafter it caches the refresh token and uses it as long as it remains valid.
diff --git a/examples/README.md b/examples/README.md
index 7211218c..37553d7a 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -300,6 +300,8 @@ $ examples/which.clj rg
A script to retrieve the version from a `pom.xml` file. See
[pom_version_get.clj](pom_version_get.clj). Written by [@wilkerlucio](https://github.com/wilkerlucio).
+See [pom_version_get_xml_zip.clj](pom_version_get_xml_zip.clj) for how to do the same using zippers.
+
Also see [pom_version_set.clj](pom_version_set.clj) to set the pom version.
## Whatsapp frequencies
diff --git a/examples/pom_version_get_xml_zip.clj b/examples/pom_version_get_xml_zip.clj
new file mode 100644
index 00000000..9caa1a9e
--- /dev/null
+++ b/examples/pom_version_get_xml_zip.clj
@@ -0,0 +1,15 @@
+(require '[babashka.deps :as deps])
+
+(deps/add-deps '{:deps {org.clojure/data.zip {:mvn/version "RELEASE"}}})
+
+(require '[clojure.data.xml :as xml]
+ '[clojure.data.zip.xml :as xmlz]
+ '[clojure.zip :as zip])
+
+(def xml "1.0.0")
+
+(-> xml
+ xml/parse-str
+ zip/xml-zip
+ (xmlz/xml1-> :pom :version zip/down zip/node))
+;; => 1.0.0
diff --git a/fs b/fs
index 05d39293..1beb91cd 160000
--- a/fs
+++ b/fs
@@ -1 +1 @@
-Subproject commit 05d392933a4e6fe0e0c3fa002c1bdeeccc995801
+Subproject commit 1beb91cd5f352d1e3a914c94e7ec25a2644b07e5
diff --git a/install b/install
index 14520a2f..e21e5a11 100755
--- a/install
+++ b/install
@@ -7,8 +7,7 @@ checksum=""
static_binary="false"
default_install_dir="/usr/local/bin"
install_dir="$default_install_dir"
-default_download_dir="/tmp"
-download_dir="$default_download_dir"
+download_dir=""
print_help() {
echo "Installs latest (or specific) version of babashka. Installation directory defaults to /usr/local/bin."
@@ -18,7 +17,7 @@ print_help() {
echo -e
echo "Defaults:"
echo " * Installation directory: ${default_install_dir}"
- echo " * Download directory: ${default_download_dir}"
+ echo " * Download directory: temporary"
if [[ -z "$checksum" ]]; then
echo " * Checksum: no"
else
@@ -29,10 +28,6 @@ print_help() {
exit 1
}
-if [[ $# -eq 1 ]]; then
- install_dir=${1:-}
-fi
-
while [[ $# -gt 0 ]]
do
key="$1"
@@ -68,6 +63,11 @@ do
esac
done
+if [[ -z "$download_dir" ]]; then
+ download_dir="$(mktemp -d)"
+ trap 'rm -rf "$download_dir"' EXIT
+fi
+
if [[ "$checksum" != "" ]] && [[ "$version" == "" ]]; then
>&2 echo "Options --checksum and --version should be provided together!"
exit 1
@@ -78,14 +78,14 @@ if [[ "$version" == "" ]]; then
fi
case "$(uname -s)" in
- Linux*) platform=linux;;
- Darwin*) platform=macos;;
+ Linux*) platform=linux;;
+ Darwin*) platform=macos;;
esac
case "$(uname -m)" in
- aarch64) arch=aarch64;;
+ aarch64) arch=aarch64;;
+ *) arch=amd64;;
esac
-arch=${arch:-amd64}
# Ugly ugly conversion of version to a comparable number
IFS='.' read -ra VER <<< "$version"
@@ -99,40 +99,42 @@ else
util="$(which tar) -zxf"
fi
-if [[ "$static_binary" == "true" ]]; then
- if [[ "$platform" != "linux" ]]; then
- >&2 echo "Static binaries are only available in Linux platform!"
- exit 1
- fi
- filename="babashka-$version-$platform-$arch-static."$ext
-else
- filename="babashka-$version-$platform-$arch."$ext
-fi
+case "$platform-$static_binary" in
+ linux-true) filename="babashka-$version-$platform-$arch-static."$ext
+ ;;
+ *-true) >&2 echo "Static binaries are only available in Linux platform! Using the non-static one..."
+ filename="babashka-$version-$platform-$arch."$ext
+ ;;
+ *) filename="babashka-$version-$platform-$arch."$ext
+ ;;
+esac
+
download_url="https://github.com/babashka/babashka/releases/download/v$version/$filename"
-mkdir -p "$download_dir"
-cd "$download_dir"
-echo -e "Downloading $download_url to $download_dir"
+# Running this part in a subshell so when it finishes we go back to the previous directory
+mkdir -p "$download_dir" && (
+ cd "$download_dir"
+ echo -e "Downloading $download_url to $download_dir"
-rm -rf "$filename"
-rm -rf "bb"
-curl -o "$filename" -sL "$download_url"
-if [[ -n "$checksum" ]]; then
- if ! echo "$checksum $filename" | sha256sum --check --status; then
- >&2 echo "Failed checksum on $filename"
- >&2 echo "Got: $(sha256sum "$filename" | cut -d' ' -f1)"
- >&2 echo "Expected: $checksum"
- exit 1
+ curl -o "$filename" -sL "$download_url"
+ if [[ -n "$checksum" ]]; then
+ if ! echo "$checksum *$filename" | shasum -a 256 --check --status; then
+ >&2 echo "Failed checksum on $filename"
+ >&2 echo "Got: $(shasum -a 256 "$filename" | cut -d' ' -f1)"
+ >&2 echo "Expected: $checksum"
+ exit 1
+ fi
fi
-fi
-$util "$filename"
-rm "$filename"
+ $util "$filename"
+ rm -f "$filename"
+)
if [[ "$download_dir" != "$install_dir" ]]
then
mkdir -p "$install_dir"
if [ -f "$install_dir/bb" ]; then
echo "Moving $install_dir/bb to $install_dir/bb.old"
+ mv -f "$install_dir/bb" "$install_dir/bb.old"
fi
mv -f "$download_dir/bb" "$install_dir/bb"
fi
diff --git a/process b/process
index 3559a706..4c6699d0 160000
--- a/process
+++ b/process
@@ -1 +1 @@
-Subproject commit 3559a70686e435504b1bed320d2e513c5bf2bb15
+Subproject commit 4c6699d06b49773d3e5c5b4c11d3334fb78cc996
diff --git a/project.clj b/project.clj
index a3ac4c96..1d23e566 100644
--- a/project.clj
+++ b/project.clj
@@ -13,6 +13,7 @@
;; for debugging Reflector.java code:
;; :java-source-paths ["sci/reflector/src-java"]
:resource-paths ["resources" "sci/resources"]
+ :test-selectors {:windows :windows}
:dependencies [[org.clojure/clojure "1.11.0-alpha1"]
[borkdude/edamame "0.0.11"]
[borkdude/graal.locking "0.0.2"]
@@ -83,7 +84,7 @@
"-Dclojure.spec.skip-macros=true"
"-Dborkdude.dynaload.aot=true"]
:main babashka.main
- :aot :all}
+ :aot [babashka.main]}
:reflection {:main babashka.impl.classes/generate-reflection-file}}
:aliases {"bb" ["with-profile" "test" "run" "-m" "babashka.main"]}
:deploy-repositories [["clojars" {:url "https://clojars.org/repo"
diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION
index 70d5b25f..c0a1ac19 100644
--- a/resources/BABASHKA_RELEASED_VERSION
+++ b/resources/BABASHKA_RELEASED_VERSION
@@ -1 +1 @@
-0.4.3
\ No newline at end of file
+0.4.6
\ No newline at end of file
diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION
index 86e5b12e..5b151cef 100644
--- a/resources/BABASHKA_VERSION
+++ b/resources/BABASHKA_VERSION
@@ -1 +1 @@
-0.4.4-SNAPSHOT
\ No newline at end of file
+0.4.7-SNAPSHOT
\ No newline at end of file
diff --git a/sci b/sci
index 4de7c780..79376504 160000
--- a/sci
+++ b/sci
@@ -1 +1 @@
-Subproject commit 4de7c78024bfdb5c52e273be372144d46228939a
+Subproject commit 7937650453b7ba9eb9ee43ea30b333b5950dc21e
diff --git a/script/bump_graal_version.clj b/script/bump_graal_version.clj
index e448d42f..786d415a 100755
--- a/script/bump_graal_version.clj
+++ b/script/bump_graal_version.clj
@@ -51,9 +51,9 @@
;; OR
;;
;; We could have them as environment variables
-(def current-graal-version "20.2.0")
+(def current-graal-version "21.0.0")
(def current-java-version "java11")
-(def valid-graal-bumps ["19.3.2" "20.1.0" "20.2.0" "20.3.0" "21.0.0"])
+(def valid-graal-bumps ["19.3.2" "20.1.0" "20.2.0" "20.3.0" "21.0.0" "21.1.0"])
(def valid-java-bumps ["java8" "java11"])
(def cl-options
diff --git a/script/setup-musl b/script/setup-musl
index bc5d90ed..118c98ec 100755
--- a/script/setup-musl
+++ b/script/setup-musl
@@ -47,16 +47,10 @@ arch=${BABASHKA_ARCH:-"x86_64"}
echo "ARCH: $arch"
cd "zlib-${ZLIB_VERSION}"
-CC=musl-gcc ./configure --static --prefix=/usr/lib/$arch-linux-musl/
+CC=musl-gcc ./configure --static --prefix="/usr/local"
make CC=musl-gcc
-sudo make install
-export CC=gcc
+make install
cd ..
-# depending on GCC version, we will have different directories here.
-# for example, for GCC 6.3.0 we will have:
-# - /usr/lib/gcc/x86_64-linux-gnu/6
-# - /usr/lib/gcc/x86_64-linux-gnu/6.3.0
-for dest_dir in /usr/lib/gcc/$arch-linux-gnu/*; do
- sudo cp -f /usr/lib/$arch-linux-musl/lib/libz.a "$dest_dir"
-done
+# Install libz.a in the correct place so ldd can find it
+install -Dm644 "/usr/local/lib/libz.a" "/usr/lib/$arch-linux-musl/libz.a"
diff --git a/script/test.bat b/script/test.bat
new file mode 100755
index 00000000..ba69e4ec
--- /dev/null
+++ b/script/test.bat
@@ -0,0 +1,11 @@
+if "%GRAALVM_HOME%"=="" (
+echo Please set GRAALVM_HOME
+exit /b
+)
+
+echo "BABASHKA_TEST_ENV: %BABASHKA_TEST_ENV%"
+
+set JAVA_HOME=%GRAALVM_HOME%
+set PATH=%GRAALVM_HOME%\bin;%PATH%
+
+call lein do clean, test :windows
diff --git a/script/uberjar b/script/uberjar
index 8a2bb9a6..7974b935 100755
--- a/script/uberjar
+++ b/script/uberjar
@@ -15,7 +15,6 @@ then
# Remove all the default features, unless explicitly set to true:
export BABASHKA_FEATURE_XML="${BABASHKA_FEATURE_XML:-false}"
export BABASHKA_FEATURE_YAML="${BABASHKA_FEATURE_YAML:-false}"
- export BABASHKA_FEATURE_CORE_ASYNC="${BABASHKA_FEATURE_CORE_ASYNC:-false}"
export BABASHKA_FEATURE_CSV="${BABASHKA_FEATURE_CSV:-false}"
export BABAHSKA_FEATURE_TRANSIT="${BABAHSKA_FEATURE_TRANSIT:-false}"
export BABASHKA_FEATURE_JAVA_TIME="${BABASHKA_FEATURE_JAVA_TIME:-false}"
diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj
index a148b8f9..fae96345 100644
--- a/src/babashka/impl/classes.clj
+++ b/src/babashka/impl/classes.clj
@@ -71,7 +71,8 @@
{:name "toString"}
{:name "toURI"}]}
java.util.Arrays
- {:methods [{:name "copyOf"}]}
+ {:methods [{:name "copyOf"}
+ {:name "copyOfRange"}]}
;; this fixes clojure.lang.Reflector for Java 11
java.lang.reflect.AccessibleObject
{:methods [{:name "canAccess"}]}}
@@ -132,11 +133,13 @@
java.lang.Object
java.lang.Process
java.lang.ProcessHandle
+ java.lang.ProcessHandle$Info
java.lang.ProcessBuilder
java.lang.ProcessBuilder$Redirect
java.lang.Runtime
java.lang.RuntimeException
java.lang.Short
+ java.lang.StackTraceElement
java.lang.String
java.lang.StringBuilder
java.lang.System
@@ -150,6 +153,7 @@
java.net.DatagramPacket
java.net.HttpURLConnection
java.net.InetAddress
+ java.net.InetSocketAddress
java.net.ServerSocket
java.net.Socket
java.net.SocketException
@@ -232,6 +236,7 @@
java.time.temporal.Temporal
java.time.temporal.TemporalAccessor
java.time.temporal.TemporalAdjuster])
+ java.util.concurrent.ExecutionException
java.util.concurrent.LinkedBlockingQueue
java.util.jar.JarFile
java.util.jar.JarEntry
@@ -247,6 +252,7 @@
java.util.Locale
java.util.Map
java.util.MissingResourceException
+ java.util.Optional
java.util.Properties
java.util.Set
java.util.UUID
@@ -344,6 +350,8 @@
java.lang.Process
(instance? java.lang.ProcessHandle v)
java.lang.ProcessHandle
+ (instance? java.lang.ProcessHandle$Info v)
+ java.lang.ProcessHandle$Info
;; added for calling .put on .environment from ProcessBuilder
(instance? java.util.Map v)
java.util.Map
@@ -398,10 +406,14 @@
:let [class-name (str c)]]
{:name class-name
:allPublicFields true}))
+ instance-checks (vec (for [c (sort (:instance-checks classes))
+ :let [class-name (str c)]]
+ ;; don't include any methods
+ {:name class-name}))
custom-entries (for [[c v] (:custom classes)
:let [class-name (str c)]]
(assoc v :name class-name))
- all-entries (concat entries constructors methods fields custom-entries)]
+ all-entries (concat entries constructors methods fields instance-checks custom-entries)]
all-entries))
(defn generate-reflection-file
diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj
index a04cb381..a7183ad6 100644
--- a/src/babashka/impl/clojure/core.clj
+++ b/src/babashka/impl/clojure/core.clj
@@ -1,7 +1,7 @@
(ns babashka.impl.clojure.core
{:no-doc true}
(:refer-clojure :exclude [future read+string clojure-version with-precision
- send-via send send-off])
+ send-via send send-off sync])
(:require [babashka.impl.common :as common]
[borkdude.graal.locking :as locking]
[clojure.core :as c]
@@ -121,6 +121,22 @@
;;;; End agents
+;;;; STM
+
+(defn -run-in-transaction [f]
+ (clojure.lang.LockingTransaction/runInTransaction f))
+
+(defmacro sync
+ "transaction-flags => TBD, pass nil for now
+ Runs the exprs (in an implicit do) in a transaction that encompasses
+ exprs and any nested calls. Starts a transaction if none is already
+ running on this thread. Any uncaught exception will abort the
+ transaction and flow out of sync. The exprs may be run more than
+ once, but any effects on Refs will be atomic."
+ {:added "1.0"}
+ [_flags-ignored-for-now & body]
+ `(clojure.core/-run-in-transaction (fn [] ~@body)))
+
(def core-extras
{;; agents
'agent (copy-core-var agent)
@@ -161,6 +177,14 @@
'*math-context* math-context
'with-precision (sci/copy-var with-precision clojure-core-ns)
'-with-precision (sci/copy-var -with-precision clojure-core-ns)
+ ;; STM
+ 'alter (sci/copy-var alter clojure-core-ns)
+ 'commute (sci/copy-var commute clojure-core-ns)
+ 'dosync (sci/copy-var dosync clojure-core-ns)
+ '-run-in-transaction (sci/copy-var -run-in-transaction clojure-core-ns)
+ 'sync (sci/copy-var sync clojure-core-ns)
+ 'ref (sci/copy-var ref clojure-core-ns)
+ 'ref-set (sci/copy-var ref-set clojure-core-ns)
;;'*clojure-version* clojure-version-var
;;'clojure-version (sci/copy-var clojure-version clojure-core-ns)
}
diff --git a/src/babashka/impl/error_handler.clj b/src/babashka/impl/error_handler.clj
index d0ad4750..e941c8ef 100644
--- a/src/babashka/impl/error_handler.clj
+++ b/src/babashka/impl/error_handler.clj
@@ -100,6 +100,9 @@
(.. e getClass getName)))
(when-let [m (.getMessage e)]
(println (str "Message: " m)))
+ (when-let [d (ex-data (.getCause e))]
+ (print (str "Data: "))
+ (prn d))
(let [{:keys [:file :line :column]} d]
(when line
(println (str "Location: "
diff --git a/src/babashka/impl/tasks.clj b/src/babashka/impl/tasks.clj
index a21a18c8..2ffbf5cc 100644
--- a/src/babashka/impl/tasks.clj
+++ b/src/babashka/impl/tasks.clj
@@ -20,7 +20,7 @@
(def log-level (sci/new-dynamic-var '*-log-level* default-log-level {:ns sci-ns}))
;; (def task-name (sci/new-dynamic-var '*-task-name* nil {:ns sci-ns}))
(def task (sci/new-dynamic-var '*task* nil {:ns sci-ns}))
-(def current-task (sci/new-dynamic-var 'current-task (fn [] @task) {:ns sci-ns}))
+(def current-task (sci/new-var 'current-task (fn [] @task) {:ns sci-ns}))
(def state (sci/new-var 'state (atom {}) {:ns sci-ns}))
(defn log-info [& strs]
@@ -31,15 +31,6 @@
(binding [*out* *err*]
(println (format "[bb %s]" (:name @task)) (str/join " " strs))))))
-#_(defn log-error [& strs]
- (let [log-level @log-level]
- (when (or
- ;; log error also in case of info level
- (identical? :info log-level)
- (identical? :error log-level))
- (binding [*out* *err*]
- (println (format "[bb %s]" (:name @task)) (str/join " " strs))))))
-
(defn- handle-non-zero [proc opts]
(when proc
(when-let [proc (deref proc)]
@@ -167,17 +158,17 @@
(format "
(let [chans (filter babashka.tasks/-chan? %s)]
(loop [cs chans]
- (let [[v p] (clojure.core.async/alts!! cs)
- [task-name v] v
- cs (filterv #(not= p %%) cs)
- ;; _ (.println System/err (str \"n: \" task-name \" v: \" v))
- ;; check for existence of v, as the channel may already have been consumed once
- _ (when v (intern *ns* (symbol task-name) v))]
- (when (instance? Throwable v)
- (throw (ex-info (ex-message v)
- {:babashka/exit 1
- :data (ex-data v)})))
- (when (seq cs)
+ (when (seq cs)
+ (let [[v p] (clojure.core.async/alts!! cs)
+ [task-name v] v
+ cs (filterv #(not= p %%) cs)
+ ;; _ (.println System/err (str \"n: \" task-name \" v: \" v))
+ ;; check for existence of v, as the channel may already have been consumed once
+ _ (when v (intern *ns* (symbol task-name) v))]
+ (when (instance? Throwable v)
+ (throw (ex-info (ex-message v)
+ {:babashka/exit 1
+ :data (ex-data v)})))
(recur cs)))))" deps)
"")
#_(format "(def %s (babashka.tasks/-wait %s))" dep dep))
@@ -234,6 +225,8 @@
prog (wrap-def task-map prog parallel? last?)]
prog)))))
+(def rand-ns (delay (symbol (str "user-" (java.util.UUID/randomUUID)))))
+
(defn format-task [init extra-paths extra-deps requires prog]
(format "
%s ;; extra-paths
@@ -264,11 +257,11 @@
(if (seq extra-deps)
(format "(babashka.deps/add-deps '%s)" (pr-str {:deps extra-deps}))
"")
- (gensym "user")
+ @rand-ns
(if (seq requires)
(format "(:require %s)" (str/join " " requires))
"")
- (str init)
+ (pr-str init)
prog))
(defn target-order
@@ -303,75 +296,70 @@
enter (:enter tasks)
leave (:leave tasks)
task (get tasks task-name)]
- (if task
- (let [m? (map? task)
- requires (get tasks :requires)
- init (get tasks :init)
- prog (if-let [depends (when m? (:depends task))]
- (let [[targets error]
- (try [(target-order tasks task-name)]
- (catch clojure.lang.ExceptionInfo e
- [nil (ex-message e)]))
- #_#_dependees (tasks->dependees targets tasks)
- task-map (cond-> {}
- enter (assoc :enter enter)
- leave (assoc :leave leave)
- parallel? (assoc :parallel parallel?))]
- (if error
- [(binding [*out* *err*]
- (println error)) 1]
- (loop [prog ""
- targets (seq targets)
- done []
- extra-paths []
- extra-deps nil
- requires requires]
- (let [t (first targets)
- targets (next targets)
- #_#_ depends-on-t (get dependees t)
- task-map (cond->
- (assoc task-map
- :name t
- #_#_:started done)
- #_#_targets (assoc :pending (vec targets))
- #_#_depends-on-t (assoc :dependents depends-on-t))]
- (if targets
- (if-let [task (get tasks t)]
- (recur (str prog "\n" (assemble-task-1 task-map task parallel?))
- targets
- (conj done t)
- (concat extra-paths (:extra-paths task))
- (merge extra-deps (:extra-deps task))
- (concat requires (:requires task)))
- [(binding [*out* *err*]
- (println "No such task:" t)) 1])
- (if-let [task (get tasks t)]
- (let [prog (str prog "\n"
- #_(wait-tasks depends) #_(apply str (map deref-task depends))
- "\n"
- (assemble-task-1 task-map task parallel? true))
- extra-paths (concat extra-paths (:extra-paths task))
- extra-deps (merge extra-deps (:extra-deps task))
- requires (concat requires (:requires task))]
- [[(format-task init extra-paths extra-deps requires prog)] nil])
- [(binding [*out* *err*]
- (println "No such task:" t)) 1]))))))
- [[(format-task
- init
- (:extra-paths task)
- (:extra-deps task)
- (concat requires (:requires task))
- (assemble-task-1 (cond-> {:name task-name}
- enter (assoc :enter enter)
- leave (assoc :leave leave)
- parallel? (assoc :parallel parallel?))
- task parallel? true))] nil])]
- (when @debug
- (binding [*out* *err*]
- (println (ffirst prog))))
- prog)
- [(binding [*out* *err*]
- (println "No such task:" task-name)) 1])))
+ (binding [*print-meta* true]
+ (if task
+ (let [m? (map? task)
+ requires (get tasks :requires)
+ init (get tasks :init)
+ prog (if (when m? (:depends task))
+ (let [[targets error]
+ (try [(target-order tasks task-name)]
+ (catch clojure.lang.ExceptionInfo e
+ [nil (ex-message e)]))
+ task-map (cond-> {}
+ enter (assoc :enter enter)
+ leave (assoc :leave leave)
+ parallel? (assoc :parallel parallel?))]
+ (if error
+ [(binding [*out* *err*]
+ (println error)) 1]
+ (loop [prog ""
+ targets (seq targets)
+ done []
+ extra-paths []
+ extra-deps nil
+ requires requires]
+ (let [t (first targets)
+ targets (next targets)
+ task-map (assoc task-map
+ :name t)]
+ (if targets
+ (if-let [task (get tasks t)]
+ (recur (str prog "\n" (assemble-task-1 task-map task parallel?))
+ targets
+ (conj done t)
+ (concat extra-paths (:extra-paths task))
+ (merge extra-deps (:extra-deps task))
+ (concat requires (:requires task)))
+ [(binding [*out* *err*]
+ (println "No such task:" t)) 1])
+ (if-let [task (get tasks t)]
+ (let [prog (str prog "\n"
+ #_(wait-tasks depends) #_(apply str (map deref-task depends))
+ "\n"
+ (assemble-task-1 task-map task parallel? true))
+ extra-paths (concat extra-paths (:extra-paths task))
+ extra-deps (merge extra-deps (:extra-deps task))
+ requires (concat requires (:requires task))]
+ [[(format-task init extra-paths extra-deps requires prog)] nil])
+ [(binding [*out* *err*]
+ (println "No such task:" t)) 1]))))))
+ [[(format-task
+ init
+ (:extra-paths task)
+ (:extra-deps task)
+ (concat requires (:requires task))
+ (assemble-task-1 (cond-> {:name task-name}
+ enter (assoc :enter enter)
+ leave (assoc :leave leave)
+ parallel? (assoc :parallel parallel?))
+ task parallel? true))] nil])]
+ (when @debug
+ (binding [*out* *err*]
+ (println (ffirst prog))))
+ prog)
+ [(binding [*out* *err*]
+ (println "No such task:" task-name)) 1]))))
(defn doc-from-task [sci-ctx tasks task]
(or (:doc task)
diff --git a/src/babashka/main.clj b/src/babashka/main.clj
index 8ec4f1df..3ee0551d 100644
--- a/src/babashka/main.clj
+++ b/src/babashka/main.clj
@@ -45,6 +45,7 @@
[sci.core :as sci]
[sci.impl.namespaces :as sci-namespaces]
[sci.impl.unrestrict :refer [*unrestricted*]]
+ [sci.impl.utils :refer [ctx-fn]]
[sci.impl.vars :as vars])
(:gen-class))
@@ -309,9 +310,15 @@ Use bb run --help to show this help output.
'start-server (fn [& args]
(apply server/start-server @common/ctx args))})
+(def input-var (sci/new-dynamic-var '*input*))
+
(def namespaces
(cond->
- {'clojure.tools.cli tools-cli-namespace
+ {'user {'*input* (ctx-fn
+ (fn [_ctx]
+ (force @input-var))
+ nil)}
+ 'clojure.tools.cli tools-cli-namespace
'clojure.java.shell shell-namespace
'babashka.wait {'wait-for-port wait/wait-for-port
'wait-for-path wait/wait-for-path}
@@ -428,13 +435,13 @@ Use bb run --help to show this help output.
Process java.lang.Process
ProcessBuilder java.lang.ProcessBuilder
Short java.lang.Short
+ StackTraceElement java.lang.StackTraceElement
String java.lang.String
StringBuilder java.lang.StringBuilder
System java.lang.System
Thread java.lang.Thread
Throwable java.lang.Throwable})
-(def input-var (sci/new-dynamic-var '*input* nil))
(def edn-readers (cond-> {}
features/yaml?
(assoc 'ordered/map @(resolve 'flatland.ordered.map/ordered-map))))
@@ -717,10 +724,7 @@ Use bb run --help to show this help output.
:namespaces (-> namespaces
(assoc 'clojure.core
(assoc core-extras
- 'load-file load-file*))
- (assoc-in ['user (with-meta '*input*
- (when-not stream?
- {:sci.impl/deref! true}))] input-var))
+ 'load-file load-file*)))
:env env
:features #{:bb :clj}
:classes classes/class-map
diff --git a/test-resources/lib_tests/babashka/run_all_libtests.clj b/test-resources/lib_tests/babashka/run_all_libtests.clj
index cc4e3c70..e7dd18d3 100644
--- a/test-resources/lib_tests/babashka/run_all_libtests.clj
+++ b/test-resources/lib_tests/babashka/run_all_libtests.clj
@@ -212,6 +212,12 @@
'honey.sql.helpers-test
'honey.sql.postgres-test)
+(test-namespaces 'slingshot.slingshot-test
+ 'slingshot.support-test
+ ;; TODO:
+ ;; 'slingshot.test-test
+ )
+
;;;; final exit code
(let [{:keys [:test :fail :error] :as m} @status]
diff --git a/test-resources/lib_tests/slingshot/slingshot_test.clj b/test-resources/lib_tests/slingshot/slingshot_test.clj
new file mode 100644
index 00000000..09938332
--- /dev/null
+++ b/test-resources/lib_tests/slingshot/slingshot_test.clj
@@ -0,0 +1,516 @@
+(ns slingshot.slingshot-test
+ (:require [clojure.test :refer :all]
+ [slingshot.slingshot :refer :all]
+ [clojure.string :as str])
+ (:import java.util.concurrent.ExecutionException))
+
+(defrecord exception-record [error-code duration-ms message])
+(defrecord x-failure [message])
+
+(def a-sphere ^{:type ::sphere} {:radius 3})
+
+(def h1 (derive (make-hierarchy) ::square ::shape))
+(def a-square ^{:type ::square} {:size 4})
+
+(def exception-1 (Exception. "exceptional"))
+(def exception-record-1 (exception-record. 6 1000 "pdf failure"))
+
+(defn mult-func [x y]
+ (let [a 7 b 11]
+ (if (= x 3)
+ (* a b x y)
+ (throw+ (x-failure. "x isn't 3... really??")))))
+
+(defmacro mega-try [body]
+ `(try+
+ ~body
+
+ ;; by class derived from Throwable
+ (catch IllegalArgumentException e#
+ [:class-iae e#])
+ (catch Exception e#
+ [:class-exception e#])
+
+ ;; by java class generically
+ (catch String e#
+ [:class-string e#])
+
+ ;; by clojure record type
+ (catch exception-record e#
+ [:class-exception-record e#])
+
+ ;; by key-value
+ (catch [:a-key 4] e#
+ [:key-yields-value e#])
+
+ ;; by multiple-key-value
+ (catch [:key1 4 :key2 5] e#
+ [:keys-yield-values e#])
+
+ ;; by key present
+ (catch (and (set? ~'%) (contains? ~'% :a-key)) e#
+ [:key-is-present e#])
+
+ ;; by clojure type, with optional hierarchy
+ (catch (isa? (type ~'%) ::sphere) e#
+ [:type-sphere (type e#) e#])
+ (catch (isa? h1 (type ~'%) ::shape) e#
+ [:type-shape-in-h1 (type e#) e#])
+
+ ;; by predicate
+ (catch nil? e#
+ [:pred-nil e#])
+ (catch keyword? e#
+ [:pred-keyword e#])
+ (catch symbol? e#
+ [:pred-symbol e#])
+ (catch map? e#
+ [:pred-map e# (meta e#)])))
+
+(deftest test-try+
+ (testing "catch by class derived from Throwable"
+ (testing "treat throwables exactly as throw does, interop with try/throw"
+ (is (= [:class-exception exception-1]
+ (mega-try (throw+ exception-1))
+ (mega-try (throw exception-1))
+ (try (throw+ exception-1)
+ (catch Exception e [:class-exception e]))
+ (try (throw exception-1)
+ (catch Exception e [:class-exception e])))))
+ (testing "IllegalArgumentException thrown by clojure/core"
+ (is (= :class-iae (first (mega-try (str/replace "foo" 1 1)))))))
+
+ (testing "catch by java class generically"
+ (is (= [:class-string "fail"] (mega-try (throw+ "fail")))))
+
+ #_(testing "catch by clojure record type"
+ (is (= [:class-exception-record exception-record-1]
+ (mega-try (throw+ exception-record-1)))))
+
+ (testing "catch by key is present"
+ (is (= [:key-is-present #{:a-key}] (mega-try (throw+ #{:a-key})))))
+
+ (testing "catch by keys and values"
+ (is (= [:key-yields-value {:a-key 4}] (mega-try (throw+ {:a-key 4}))))
+ (is (= [:keys-yield-values {:key1 4 :key2 5}]
+ (mega-try (throw+ {:key1 4 :key2 5})))))
+
+ (testing "catch by clojure type with optional hierarchy"
+ (is (= [:type-sphere ::sphere a-sphere] (mega-try (throw+ a-sphere))))
+ (is (= [:type-shape-in-h1 ::square a-square] (mega-try (throw+ a-square)))))
+
+ (testing "catch by predicate"
+ (is (= [:pred-nil nil] (mega-try (throw+ nil))))
+ (is (= [:pred-keyword :awesome] (mega-try (throw+ :awesome))))
+ (is (= [:pred-symbol 'yuletide] (mega-try (throw+ 'yuletide))))
+ (is (= [:pred-map {:error-code 4} nil] (mega-try (throw+ {:error-code 4}))))
+ (testing "preservation of metadata"
+ (is (= [:pred-map {:error-code 4} {:severity 4}]
+ (mega-try (throw+ ^{:severity 4} {:error-code 4})))))))
+
+(deftest test-clauses
+ (let [bumps (atom 0)
+ bump (fn [] (swap! bumps inc))]
+ (is (nil? (try+)))
+ (is (nil? (try+ (catch integer? i (inc i)))))
+ (is (nil? (try+ (finally (bump)))))
+ (is (nil? (try+ (catch integer? i (inc i)) (finally (bump)))))
+ (is (nil? (try+ (catch integer? i (inc i)) (catch map? m m)
+ (finally (bump)))))
+
+ (is (= 3 (try+ 3)))
+ (is (= 3 (try+ 3 (catch integer? i 4))))
+ (is (= 3 (try+ 3 (finally (bump)))))
+ (is (= 3 (try+ 3 (catch integer? i 4) (finally (bump)))))
+ (is (= 4 (try+ (throw+ 3) (catch integer? i (inc i)) (finally (bump)))))
+ (is (= 4 (try+ (throw+ 3) (catch integer? i (inc i)) (catch map? m m)
+ (finally (bump)))))
+ (is (= 4 (try+ (throw+ {:sel 4}) (catch integer? i (inc i))
+ (catch map? m (:sel m)) (finally (bump)))))
+
+ (is (= 4 (try+ 3 4)))
+ (is (= 4 (try+ 3 4 (catch integer? i 4))))
+ (is (= 4 (try+ 3 4 (finally (bump)))))
+ (is (= 4 (try+ 3 4 (catch integer? i 4) (finally (bump)))))
+ (is (= 5 (try+ (throw+ 4) 4 (catch integer? i (inc i)) (finally (bump)))))
+ (is (= 11 @bumps))))
+
+(defn ax [] (throw+ 1))
+(defn bx [] (try+ (ax) (catch integer? p (throw+ 2))))
+(defn cx [] (try+ (bx) (catch integer? q (throw+ 3))))
+(defn dx [] (try+ (cx) (catch integer? r (throw+ 4))))
+(defn ex [] (try+ (dx) (catch integer? s (throw+ 5))))
+(defn fx [] (try+ (ex) (catch integer? t (throw+ 6))))
+(defn gx [] (try+ (fx) (catch integer? u (throw+ 7))))
+(defn hx [] (try+ (gx) (catch integer? v (throw+ 8))))
+(defn ix [] (try+ (hx) (catch integer? w &throw-context)))
+
+(defn next-context [x]
+ (-> x :cause get-throw-context))
+
+(deftest test-throw-context
+ (let [context (ix)
+ context1 (next-context context)
+ context2 (next-context context1)]
+
+ (is (= #{:object :message :cause :stack-trace :wrapper :throwable}
+ (set (keys context))
+ (set (keys context1))
+ (set (keys context2))))
+ (is (= 8 (-> context :object)))
+ (is (= 7 (-> context1 :object)))
+ (is (= 6 (-> context2 :object)))))
+
+(defn e []
+ (try+
+ (throw (Exception. "uncaught"))
+ (catch integer? i i)))
+
+(defn f []
+ (try+
+ (throw+ 3.2)
+ (catch integer? i i)))
+
+
+(defn g []
+ (try+
+ (throw+ 3.2 "wasn't caught")
+ (catch integer? i i)))
+
+(deftest test-uncaught
+ (is (thrown-with-msg? Exception #"^uncaught$" (e)))
+ (is (thrown-with-msg? Exception #"^throw\+: .*" (f)))
+ (is (thrown-with-msg? Exception #"wasn't caught" (g))))
+
+(defn h []
+ (try+
+ (try+
+ (throw+ 0)
+ (catch zero? e
+ (throw+)))
+ (catch zero? e
+ :zero)))
+
+(deftest test-rethrow
+ (is (= :zero (h))))
+
+(defn i []
+ (try
+ (try+
+ (doall (map (fn [x] (throw+ (str x))) [1]))
+ (catch string? x
+ x))
+ (catch Throwable x)))
+
+(defn j []
+ (try+
+ (let [fut (future (throw+ "whoops"))]
+ @fut)
+ (catch string? e
+ e)))
+
+(deftest test-issue-5
+ (is (= "1" (i)))
+ (is (= "whoops" (j))))
+
+(deftest test-unmacroed-pct
+ (is (= :was-eee (try+ (throw+ "eee")
+ (catch (= % "eee") _ :was-eee)
+ (catch string? _ :no!)))))
+
+(deftest test-x-ray-vision
+ (let [[val wrapper] (try+
+ (try
+ (try
+ (try
+ (throw+ "x-ray!")
+ (catch Throwable x
+ (throw (RuntimeException. x))))
+ (catch Throwable x
+ (throw (ExecutionException. x))))
+ (catch Throwable x
+ (throw (RuntimeException. x))))
+ (catch string? x
+ [x (:throwable &throw-context)]))]
+ (is (= "x-ray!" val))
+ (is (= "x-ray!" (get-thrown-object wrapper)))))
+
+(deftest test-catching-wrapper
+ (let [e (Exception.)]
+ (try
+ (try+
+ (throw e)
+ (catch Exception _
+ (throw+ :a "msg: %s" %)))
+ (is false)
+ (catch Exception s
+ (is (= "msg: :a" (.getMessage s)))
+ (is (= e (.getCause s)))))))
+
+(deftest test-eval-object-once
+ (let [bumps (atom 0)
+ bump (fn [] (swap! bumps inc))]
+ (try+
+ (throw+ (bump) "this is it: %s %s %s" % % %)
+ (catch Object _))
+ (is (= @bumps 1))))
+
+(deftest test-get-throw-context
+ (let [object (Object.)
+ exception1 (Exception.)
+ exception2 (Exception. "ex1" exception1)
+ t1 (try
+ (throw+ object)
+ (catch Throwable t t))
+ t2 (try
+ (throw+ exception2)
+ (catch Throwable t t))
+ t3 (try
+ (throw exception2)
+ (catch Throwable t t))]
+ (is (= #{:object :message :cause :stack-trace :wrapper
+ :throwable}
+ (-> t1 get-throw-context keys set)))
+ (is (= #{:object :message :cause :stack-trace :throwable}
+ (-> t2 get-throw-context keys set)))
+ (is (= #{:object :message :cause :stack-trace :throwable}
+ (-> t3 get-throw-context keys set)))
+
+ (is (identical? object (:object (get-throw-context t1))))
+ (is (identical? exception2 (:object (get-throw-context t2))))
+ (is (identical? exception2 (:object (get-throw-context t3))))
+
+ (is (identical? exception1 (:cause (get-throw-context t2))))
+ (is (identical? exception1 (:cause (get-throw-context t3))))
+ (is (= "ex1" (:message (get-throw-context t2))))
+ (is (= "ex1" (:message (get-throw-context t3))))))
+
+(deftest test-get-thrown-object
+ (let [object (Object.)
+ exception (Exception.)
+ t1 (try
+ (throw+ object)
+ (catch Throwable t t))
+ t2 (try
+ (throw+ exception)
+ (catch Throwable t t))
+ t3 (try
+ (throw exception)
+ (catch Throwable t t))]
+ (is (identical? object (get-thrown-object t1)))
+ (is (identical? exception (get-thrown-object t2)))
+ (is (identical? exception (get-thrown-object t3)))))
+
+(deftest test-wrapper-and-throwable
+ (let [context (try+
+ (try
+ (throw+ :afp "wrapper-0")
+ (catch Exception e
+ (throw (RuntimeException. "wrapper-1" e))))
+ (catch Object _
+ &throw-context))]
+ (is (= "wrapper-0" (.getMessage ^Throwable (:wrapper context))))
+ (is (= "wrapper-1" (.getMessage ^Throwable (:throwable context))))))
+
+(deftest test-inline-predicate
+ (is (= :not-caught (try+
+ (throw+ {:foo true})
+ (catch #(-> % :foo (= false)) data
+ :caught)
+ (catch Object _
+ :not-caught)))))
+
+(defn gen-body
+ [rec-sym throw?]
+ (let [body `(swap! ~rec-sym #(conj % :body))]
+ (if throw?
+ (list 'do body `(throw+ (Exception.)))
+ body)))
+
+(defn gen-catch-clause
+ [rec-sym]
+ `(catch Exception e# (swap! ~rec-sym #(conj % :catch))))
+
+(defn gen-else-clause
+ [rec-sym broken?]
+ (let [else-body `(swap! ~rec-sym #(conj % :else))]
+ (if broken?
+ (list 'else (list 'do else-body `(throw+ (Exception.))))
+ (list 'else else-body))))
+
+(defn gen-finally-clause
+ [rec-sym]
+ `(finally (swap! ~rec-sym #(conj % :finally))))
+
+(defn gen-try-else-form
+ "Generate variations of (try ... (else ...) ...) forms, which (when eval'd)
+ will return a vector describing the sequence in which things were evaluated,
+ e.g. [:body :catch :finally]"
+ [throw? catch? finally? broken-else?]
+ (let [rec-sym (gensym "rec")
+ body (gen-body rec-sym throw?)
+ catch-clause (if catch? (gen-catch-clause rec-sym))
+ else-clause (gen-else-clause rec-sym broken-else?)
+ finally-clause (if finally? (gen-finally-clause rec-sym))]
+ `(let [~rec-sym (atom [])]
+ (try+
+ ~(remove nil? `(try+
+ ~body
+ ~catch-clause
+ ~else-clause
+ ~finally-clause))
+ (catch Object e#
+ ;; if the inner try+ threw, report it as a :bang! in the return vec
+ (swap! ~rec-sym #(conj % :bang!))))
+ @~rec-sym)))
+
+(deftest test-else
+ (doseq [throw? [true false]
+ catch? [true false]
+ broken-else? [true false]
+ finally? [true false]]
+ (testing (str "test-else: throw? " throw? " catch? " catch?
+ " broken-else? " broken-else? " finally? " finally?)
+ (let [try-else-form (gen-try-else-form throw? catch? finally? broken-else?)
+ actual (eval try-else-form)
+ expected (vec (remove nil?
+ [:body
+ (if (and throw? catch?) :catch)
+ (if (not throw?) :else)
+ (if finally? :finally)
+ ;; expect an escaped exception when either:
+ ;; a) the else clause runs, and throws
+ ;; b) the body throws, and is not caught
+ (if (or (and (not throw?) broken-else?)
+ (and throw? (not catch?))) :bang!)]))]
+ (is (= actual expected))))))
+
+(deftest test-reflection
+ (try+
+ nil
+ (catch Exception e
+ (.getMessage e))))
+
+(deftest test-ex-info-compatibility
+ (let [data {:type :fail :reason :not-found}
+ message "oops"
+ wrapper (ex-info message data)
+ rte1 (RuntimeException. "one" wrapper)
+ rte2 (RuntimeException. "two" rte1)
+ direct (try+
+ (throw wrapper)
+ (catch [:type :fail] e
+ &throw-context)
+ (catch Object _
+ :whoops))
+ cause-chain (try+
+ (throw rte2)
+ (catch [:type :fail] e
+ &throw-context)
+ (catch Object _
+ :whoops))]
+ (is (= (:object direct) data))
+ (is (= (:object cause-chain) data))
+ (is (= (:message direct) message))
+ (is (= (:message cause-chain) message))
+ (is (= (:wrapper direct) wrapper))
+ (is (= (:wrapper cause-chain) wrapper))
+ (is (= (:throwable direct) wrapper))
+ (is (= (:throwable cause-chain) rte2))))
+
+;; helpers for test-optional-cause
+
+(defmacro caught-result [& body]
+ `(try+
+ ~@body
+ (catch Object ~'o
+ [(:cause ~'&throw-context)
+ (:message ~'&throw-context)])))
+
+(defmacro caught-result-from-catch [cause & body]
+ `(caught-result
+ (try+
+ (throw+ ~cause)
+ (catch Object ~'o
+ ~@body))))
+
+(deftest test-optional-cause
+ (let [imp (Exception. "I did it implicitly.")
+ exp (Exception. "I did it explicitly.")
+ def-msg "throw+: 1"
+ msg "message two %s"
+ fmt "aha! %s"
+ fmt-msg "aha! 1"
+ fmt2 "%s leading to %s"
+ fmt2-msg "1 leading to [1 1]"
+
+ ;; throw from outside catch, no implicit cause
+
+ result1 (caught-result (throw+ 1))
+ result2 (caught-result (throw+ 1 msg))
+ result3 (caught-result (throw+ 1 fmt %))
+ result4 (caught-result (throw+ 1 fmt2 % [% %]))
+
+ result5 (caught-result (throw+ 1 nil))
+ result6 (caught-result (throw+ 1 nil msg))
+ result7 (caught-result (throw+ 1 nil fmt %))
+ result8 (caught-result (throw+ 1 nil fmt2 % [% %]))
+
+ result9 (caught-result (throw+ 1 exp))
+ result10 (caught-result (throw+ 1 exp msg))
+ result11 (caught-result (throw+ 1 exp fmt %))
+ result12 (caught-result (throw+ 1 exp fmt2 % [% %]))
+
+ ;; throw from inside catch, implicit cause available
+
+ result13 (caught-result-from-catch imp (throw+))
+
+ result14 (caught-result-from-catch imp (throw+ 1))
+ result15 (caught-result-from-catch imp (throw+ 1 msg))
+ result16 (caught-result-from-catch imp (throw+ 1 fmt %))
+ result17 (caught-result-from-catch imp (throw+ 1 fmt2 % [% %]))
+
+ result18 (caught-result-from-catch imp (throw+ 1 nil))
+ result19 (caught-result-from-catch imp (throw+ 1 nil msg))
+ result20 (caught-result-from-catch imp (throw+ 1 nil fmt %))
+ result21 (caught-result-from-catch imp (throw+ 1 nil fmt2 % [% %]))
+
+ result22 (caught-result-from-catch imp (throw+ 1 exp))
+ result23 (caught-result-from-catch imp (throw+ 1 exp msg))
+ result24 (caught-result-from-catch imp (throw+ 1 exp fmt %))
+ result25 (caught-result-from-catch imp (throw+ 1 exp fmt2 % [% %]))]
+
+ (testing "outside catch"
+ (testing "implicit cause"
+ (is (= result1 [nil def-msg]))
+ (is (= result2 [nil msg]))
+ (is (= result3 [nil fmt-msg]))
+ (is (= result4 [nil fmt2-msg])))
+ (testing "erased cause"
+ (is (= result5 [nil def-msg]))
+ (is (= result6 [nil msg]))
+ (is (= result7 [nil fmt-msg]))
+ (is (= result8 [nil fmt2-msg])))
+ (testing "explicit cause"
+ (is (= result9 [exp def-msg]))
+ (is (= result10 [exp msg]))
+ (is (= result11 [exp fmt-msg]))
+ (is (= result12 [exp fmt2-msg]))))
+ (testing "inside catch"
+ (testing "rethrow"
+ (is (= result13 [nil "I did it implicitly."])))
+ (testing "implicit cause"
+ (is (= result14 [imp def-msg]))
+ (is (= result15 [imp msg]))
+ (is (= result16 [imp fmt-msg]))
+ (is (= result17 [imp fmt2-msg])))
+ (testing "erased cause"
+ (is (= result18 [nil def-msg]))
+ (is (= result19 [nil msg]))
+ (is (= result20 [nil fmt-msg]))
+ (is (= result21 [nil fmt2-msg])))
+ (testing "explicit cause"
+ (is (= result22 [exp def-msg]))
+ (is (= result23 [exp msg]))
+ (is (= result24 [exp fmt-msg]))
+ (is (= result25 [exp fmt2-msg]))))))
diff --git a/test-resources/lib_tests/slingshot/support_test.clj b/test-resources/lib_tests/slingshot/support_test.clj
new file mode 100644
index 00000000..12d2c142
--- /dev/null
+++ b/test-resources/lib_tests/slingshot/support_test.clj
@@ -0,0 +1,111 @@
+(ns slingshot.support-test
+ (:require [clojure.test :refer :all]
+ [slingshot.slingshot :refer [throw+ try+]]
+ [slingshot.support :refer :all])
+ (:import (java.util.concurrent ExecutionException)))
+
+(deftest test-parse-try+
+ (let [f parse-try+]
+ (is (= [nil nil nil nil] (f ())))
+
+ (is (= ['(1) nil nil nil] (f '(1))))
+ (is (= [nil '((catch 1)) nil nil] (f '((catch 1)))))
+ (is (= [nil nil '(else 1) nil] (f '((else 1)))))
+ (is (= [nil nil nil '(finally 1)] (f '((finally 1)))))
+
+ (is (= ['(1) '((catch 1)) nil nil] (f '(1 (catch 1)))))
+ (is (= ['(1) nil '(else 1) nil] (f '(1 (else 1)))))
+ (is (= ['(1) nil nil '(finally 1)] (f '(1 (finally 1)))))
+
+ (is (= ['(1) '((catch 1)) nil '(finally 1)]
+ (f '(1 (catch 1) (finally 1)))))
+ (is (= ['(1) '((catch 1) (catch 2)) nil '(finally 1)]
+ (f '(1 (catch 1) (catch 2) (finally 1)))))
+ (is (= ['(1) '((catch 1)) '(else 1) nil]
+ (f '(1 (catch 1) (else 1)))))
+ (is (= ['(1) '((catch 1) (catch 2)) '(else 1) nil]
+ (f '(1 (catch 1) (catch 2) (else 1)))))
+
+ (is (= [nil nil '(else 1) '(finally 1)]
+ (f '((else 1) (finally 1)))))
+ (is (= ['(1) nil '(else 1) '(finally 1)]
+ (f '(1 (else 1) (finally 1)))))
+ (is (= [nil '((catch 1)) '(else 1) nil]
+ (f '((catch 1) (else 1)))))
+ (is (= ['(1) '((catch 1)) '(else 1) nil]
+ (f '(1 (catch 1) (else 1)))))
+
+ (is (thrown? IllegalArgumentException (f '((catch 1) (1)))))
+ (is (thrown? IllegalArgumentException (f '((finally 1) (1)))))
+ (is (thrown? IllegalArgumentException (f '((finally 1) (catch 1)))))
+ (is (thrown? IllegalArgumentException (f '((finally 1) (finally 2)))))
+ (is (thrown? IllegalArgumentException (f '((else 1) (1)))))
+ (is (thrown? IllegalArgumentException (f '((else 1) (catch 1)))))
+ (is (thrown? IllegalArgumentException (f '((else 1) (else 2)))))))
+
+(defn stack-trace-fn []
+ (stack-trace))
+
+#_(deftest test-stack-trace
+ (let [{:keys [methodName className]} (-> (stack-trace-fn) first bean)]
+ (is (= methodName "invoke"))
+ (is (re-find #"stack_trace_fn" className))))
+
+(deftest test-resolve-local
+ (let [a 4]
+ (is (= 4 (resolve-local a)))
+ (is (nil? (resolve-local b)))))
+
+(deftest test-wrap
+ (let [tmessage "test-wrap-1"
+ tobject 4
+ tcause (Exception.)
+ tstack-trace (stack-trace)
+ tdata {:object tobject}
+ tcontext (assoc tdata
+ :message tmessage
+ :cause tcause
+ :stack-trace tstack-trace)
+ tthrowable (wrap tcontext)
+ {:keys [message cause data stackTrace]} (bean tthrowable)]
+ (is (ex-data tthrowable))
+ (is (= [message cause (seq stackTrace) data]
+ [tmessage tcause (seq tstack-trace) tdata]))))
+
+(def test-hooked (atom nil))
+
+(deftest test-throw-hook
+ (binding [*throw-hook* #(reset! test-hooked %)]
+ (throw+ "throw-hook-string")
+ (is (= (set (keys @test-hooked))
+ (set [:object :message :cause :stack-trace])))
+ (is (= "throw-hook-string" (:object @test-hooked))))
+ (binding [*throw-hook* (fn [x] 42)]
+ (is (= (throw+ "something") 42))))
+
+(def catch-hooked (atom nil))
+
+(defn catch-hook-return [object]
+ (fn [x] (assoc x :catch-hook-return object)))
+
+(defn catch-hook-throw [object]
+ (fn [x] (assoc x :catch-hook-throw object)))
+
+(deftest test-catch-hook
+ (binding [*catch-hook* #(reset! catch-hooked %)]
+ (try+ (throw+ "catch-hook-string") (catch string? x x))
+ (is (= (set (keys @catch-hooked))
+ (set [:object :message :cause :stack-trace :wrapper :throwable])))
+ (is (= "catch-hook-string" (:object @catch-hooked))))
+ (binding [*catch-hook* (catch-hook-return 42)]
+ (is (= 42 (try+ (throw+ "boo") (catch string? x x)))))
+ (binding [*catch-hook* (catch-hook-throw (IllegalArgumentException. "bleh"))]
+ (is (thrown-with-msg? IllegalArgumentException #"bleh"
+ (try+ (throw+ "boo") (catch string? x x)))))
+ (is (= "soup!"
+ (try+
+ (binding [*catch-hook* (catch-hook-throw "soup!")]
+ (try+
+ (throw+ "boo")
+ (catch string? x x)))
+ (catch string? x x)))))
diff --git a/test-resources/lib_tests/slingshot/test_test.clj b/test-resources/lib_tests/slingshot/test_test.clj
new file mode 100644
index 00000000..b156c289
--- /dev/null
+++ b/test-resources/lib_tests/slingshot/test_test.clj
@@ -0,0 +1,8 @@
+(ns slingshot.test-test
+ (:require [clojure.test :refer :all]
+ [slingshot.slingshot :refer [throw+]]
+ [slingshot.test]))
+
+(deftest test-slingshot-test-macros
+ (is (thrown+? string? (throw+ "test")))
+ (is (thrown+-with-msg? string? #"th" (throw+ "test" "hi there"))))
diff --git a/test/babashka/bb_edn_test.clj b/test/babashka/bb_edn_test.clj
index ae73f7fa..6c43a6ea 100644
--- a/test/babashka/bb_edn_test.clj
+++ b/test/babashka/bb_edn_test.clj
@@ -236,7 +236,28 @@
:task (do (Thread/sleep 10)
(+ 1 2 3))}
c (do (Thread/sleep 10) :c)}}
- (is (= [6 6 :c] (bb "run" "--prn" "a")))))))
+ (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*]))}}
+ (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]
+ server [:foo :bar]]
+ (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"))))))
(deftest list-tasks-test
(test-utils/with-config {}
diff --git a/test/babashka/error_test.clj b/test/babashka/error_test.clj
index 857ca787..25914e35 100644
--- a/test/babashka/error_test.clj
+++ b/test/babashka/error_test.clj
@@ -169,3 +169,33 @@ user/quux - :1:15
user/quux - :1:1
user/bar - :1:69
user - :1:91"))))
+
+(deftest print-exception-data-test
+ (testing "output of uncaught ExceptionInfo"
+ (let [output (try (tu/bb nil "(let [d {:zero 0 :one 1}] (throw (ex-info \"some msg\" d)))")
+ (catch Exception e (ex-message e)))]
+ (multiline-equals output
+ "----- Error --------------------------------------------------------------------
+Type: clojure.lang.ExceptionInfo
+Message: some msg
+Data: {:zero 0, :one 1}
+Location: :1:27
+
+----- Context ------------------------------------------------------------------
+1: (let [d {:zero 0 :one 1}] (throw (ex-info \"some msg\" d)))
+ ^--- some msg
+
+----- Locals -------------------------------------------------------------------
+d: {:zero 0, :one 1}")))
+ (testing "output of ordinary Exception"
+ (let [output (try (tu/bb nil "(throw (Exception. \"some msg\"))")
+ (catch Exception e (ex-message e)))]
+ (multiline-equals output
+ "----- Error --------------------------------------------------------------------
+Type: java.lang.Exception
+Message: some msg
+Location: :1:1
+
+----- Context ------------------------------------------------------------------
+1: (throw (Exception. \"some msg\"))
+ ^--- some msg"))))
diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj
index 08dddee0..822fb802 100644
--- a/test/babashka/impl/nrepl_server_test.clj
+++ b/test/babashka/impl/nrepl_server_test.clj
@@ -180,7 +180,7 @@
"session" session "id" (new-id!)})
(dotimes [_ 3]
(let [reply (read-reply in session @id)]
- (is (= "Hello\n" (:out reply)))))))))
+ (is (= "Hello\n" (tu/normalize (:out reply))))))))))
(deftest nrepl-server-test
(let [proc-state (atom nil)
diff --git a/test/babashka/impl/repl_test.clj b/test/babashka/impl/repl_test.clj
index d9cf7b70..a1bd730b 100644
--- a/test/babashka/impl/repl_test.clj
+++ b/test/babashka/impl/repl_test.clj
@@ -2,6 +2,7 @@
(:require
[babashka.impl.pprint :refer [pprint-namespace]]
[babashka.impl.repl :refer [start-repl!]]
+ [babashka.test-utils :as tu]
[clojure.string :as str]
[clojure.test :as t :refer [deftest is]]
[sci.core :as sci]
@@ -20,18 +21,20 @@
:namespaces {'clojure.pprint pprint-namespace}})))
(defn assert-repl [expr expected]
- (is (str/includes? (sci/with-out-str
- (sci/with-in-str (str expr "\n:repl/quit")
- (repl!))) expected)))
+ (is (str/includes? (tu/normalize
+ (sci/with-out-str
+ (sci/with-in-str (str expr "\n:repl/quit")
+ (repl!)))) expected)))
(defn assert-repl-error [expr expected]
(is (str/includes?
- (let [sw (java.io.StringWriter.)]
- (sci/binding [sci/out (java.io.StringWriter.)
- sci/err sw]
- (sci/with-in-str (str expr "\n:repl/quit")
- (repl!)))
- (str sw)) expected)))
+ (tu/normalize
+ (let [sw (java.io.StringWriter.)]
+ (sci/binding [sci/out (java.io.StringWriter.)
+ sci/err sw]
+ (sci/with-in-str (str expr "\n:repl/quit")
+ (repl!)))
+ (str sw))) expected)))
(deftest repl-test
(assert-repl "1" "1")
diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj
index 4fb329b3..a56bfc87 100644
--- a/test/babashka/main_test.clj
+++ b/test/babashka/main_test.clj
@@ -17,7 +17,7 @@
:eof nil}
(apply test-utils/bb (when (some? input) (str input)) (map str args))))
-(deftest parse-opts-test
+(deftest ^:windows parse-opts-test
(is (= "1667"
(:nrepl (main/parse-opts ["--nrepl-server"]))))
(is (= "1666"
@@ -52,17 +52,17 @@
(is (= '("-e" "1") (bb nil "-e" "*command-line-args*" "--" "-e" "1")))
(let [v (bb nil "--describe")]
(is (:babashka/version v))
- (is (:feature/xml v)))
- )
+ (is (:feature/xml v))))
-(deftest version-test
+
+(deftest ^:windows version-test
(is (= [1 0 0] (main/parse-version "1.0.0-SNAPSHOT")))
(is (main/satisfies-min-version? "0.1.0"))
(is (main/satisfies-min-version? "0.1.0-SNAPSHOT"))
(is (not (main/satisfies-min-version? "300.0.0")))
(is (not (main/satisfies-min-version? "300.0.0-SNAPSHOT"))))
-(deftest print-error-test
+(deftest ^:windows print-error-test
(is (thrown-with-msg? Exception #"java.lang.NullPointerException"
(bb nil "(subs nil 0 0)"))))
@@ -131,8 +131,8 @@
(doseq [s res]
(is (not-empty s)))))
-(deftest malformed-command-line-args-test
- (is (thrown-with-msg? Exception #"File does not exist: non-existing\n"
+(deftest ^:windows malformed-command-line-args-test
+ (is (thrown-with-msg? Exception #"File does not exist: non-existing"
(bb nil "-f" "non-existing"))))
(deftest ssl-test
@@ -178,10 +178,11 @@
name)))))
(testing "print source from file on classpath"
(is (= "(defn foo [x y]\n (+ x y))\n"
- (bb nil
- "-cp" dir
- "-e" (format "(require '[clojure.repl :refer [source]] '[%s])" name)
- "-e" (format "(with-out-str (source %s/foo))" name)))))))
+ (test-utils/normalize
+ (bb nil
+ "-cp" dir
+ "-e" (format "(require '[clojure.repl :refer [source]] '[%s])" name)
+ "-e" (format "(with-out-str (source %s/foo))" name))))))))
(deftest eval-test
(is (= "120\n" (test-utils/bb nil "(eval '(do (defn foo [x y] (+ x y))
@@ -388,8 +389,7 @@
(is (= "hello" (bb nil "(doto (java.lang.Thread. (fn [] (prn \"hello\"))) (.start) (.join)) nil"))))
(deftest dynvar-test
- (is (= 1 (bb nil "(binding [*command-line-args* 1] *command-line-args*)")))
- (is (= 1 (bb nil "(binding [*input* 1] *input*)"))))
+ (is (= 1 (bb nil "(binding [*command-line-args* 1] *command-line-args*)"))))
(deftest file-in-error-msg-test
(is (thrown-with-msg? Exception #"error.bb"
@@ -468,8 +468,8 @@
;; TODO: refactor into individual unit tests
;; One for downloading a small file and one for unzipping.
#_(is (try (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb")))
- (catch Exception e
- (is (str/includes? (str e) "timed out"))))))
+ (catch Exception e
+ (is (str/includes? (str e) "timed out"))))))
(deftest get-message-on-exception-info-test
(is "foo" (bb nil "(try (throw (ex-info \"foo\" {})) (catch Exception e (.getMessage e)))")))
@@ -639,6 +639,23 @@ true")))
(is (str/blank? (with-out-str (main/main "doc" "non-existing"))))
(is (= 1 (main/main "doc" "non-existing")))))
+(deftest process-handler-info-test
+ (when test-utils/native?
+ (is (= ["-e" "(vec (.get (.arguments (.info (java.lang.ProcessHandle/current)))))"]
+ (bb nil "-e" "(vec (.get (.arguments (.info (java.lang.ProcessHandle/current)))))")))
+ (is (str/ends-with?
+ (bb nil "-e" "(.get (.command (.info (java.lang.ProcessHandle/current))))")
+ "bb"))))
+
+(deftest interop-concurrency-test
+ (is (= ["true" 3] (last (bb nil "-e"
+ "
+(def f (fn [_]
+ [(String/valueOf true)
+ (.length \"foo\")]))
+
+(vec (pmap f (map str (range 10000))))")))))
+
;;;; Scratch
(comment
diff --git a/test/babashka/test_utils.clj b/test/babashka/test_utils.clj
index c3f18752..79cd85c2 100644
--- a/test/babashka/test_utils.clj
+++ b/test/babashka/test_utils.clj
@@ -6,12 +6,19 @@
[babashka.main :as main]
[babashka.process :as p]
[clojure.edn :as edn]
+ [clojure.string :as str]
[clojure.test :as test :refer [*report-counters*]]
[sci.core :as sci]
[sci.impl.vars :as vars]))
(set! *warn-on-reflection* true)
+
+(defn normalize [s]
+ (if main/windows?
+ (str/replace s "\r\n" "\n")
+ s))
+
(def ^:dynamic *bb-edn-path* nil)
(defmethod clojure.test/report :begin-test-var [m]
@@ -55,7 +62,7 @@
(with-in-str input-or-opts (apply main/main args))
(apply main/main args)))]
(if (zero? res)
- (str os)
+ (normalize (str os))
(do
(println (str os))
(throw (ex-info (str es)