From a4b4ce43a4fe6e2614c7e5195a3ffad2d97e70b2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 21 Feb 2020 21:32:28 +0100 Subject: [PATCH 001/264] Add java.time.temporal.ChronoUnit class (#271) * Adding java.time.temporal.ChronoUnit to classes.clj This enables the two following kinds of calculations between LocalDateTime, LocalTime, Instant and other Temporal descendants: ChronoUnit.MILLIS.between(temporalOne, temporalTwo) temporalOne.until(temporalTwo, Chronounit.HOURS) and I assume a lot of other operations which require time units. * Add unit test Co-authored-by: Matias Bjarland --- doc/dev.md | 3 +++ src/babashka/impl/classes.clj | 1 + test/babashka/java_time_test.clj | 6 +++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/dev.md b/doc/dev.md index 4244149e..19f5151e 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -57,6 +57,9 @@ Keep notes here about how adding libraries and classes to Babashka affects the b +2020/02/21, +Added java.time.temporal.ChronoUnit +40651596 - 40598260 = 53kb added. 2020/02/19, e43727955a2cdabd2bb0189c20dd7f9a18156fc9 Added fipp.edn/pprint diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index e0451f08..d69a0d9a 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -83,6 +83,7 @@ java.time.ZonedDateTime java.time.ZoneId java.time.ZoneOffset + java.time.temporal.ChronoUnit java.time.temporal.TemporalAccessor java.util.regex.Pattern java.util.Base64 diff --git a/test/babashka/java_time_test.clj b/test/babashka/java_time_test.clj index 65b22709..c66fb8e4 100644 --- a/test/babashka/java_time_test.clj +++ b/test/babashka/java_time_test.clj @@ -16,4 +16,8 @@ (is (= "18-12-2019 16:01:41" (bb '(.format (java.time.LocalDateTime/parse "2019-12-18T16:01:41.485") - (java.time.format.DateTimeFormatter/ofPattern "dd-MM-yyyy HH:mm:ss")))))) + (java.time.format.DateTimeFormatter/ofPattern "dd-MM-yyyy HH:mm:ss"))))) + (is (number? (bb " +(let [x (java.time.LocalDateTime/parse \"2019-12-18T16:01:41.485\") + y (java.time.LocalDateTime/now)] + (.between java.time.temporal.ChronoUnit/MINUTES x y))")))) From b8469180f9a00c9f2f8ec032c3ff38de1729cd0f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 12:04:18 +0100 Subject: [PATCH 002/264] Linux builds are statically linked --- .circleci/config.yml | 1 + script/compile | 49 ++++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a7cb1471..f306e408 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,6 +70,7 @@ jobs: GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0 BABASHKA_PLATFORM: linux # used in release script BABASHKA_TEST_ENV: native + BABASHKA_STATIC: true steps: - checkout - run: diff --git a/script/compile b/script/compile index fbb59dc7..97d41852 100755 --- a/script/compile +++ b/script/compile @@ -15,35 +15,34 @@ fi BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) -# # We also need to AOT sci, else something didn't work in the Mac build on CircleCI -# # See https://github.com/oracle/graal/issues/1613 -# ( cd /tmp; git clone https://github.com/borkdude/sci 2> /dev/null || true ) -# mkdir -p src/sci -# cp -R /tmp/sci/src/* src - export JAVA_HOME=$GRAALVM_HOME lein with-profiles +reflection do run lein do clean, uberjar -$GRAALVM_HOME/bin/native-image \ - -jar target/babashka-$BABASHKA_VERSION-standalone.jar \ - -H:Name=bb \ - -H:+ReportExceptionStackTraces \ - -J-Dclojure.spec.skip-macros=true \ - -J-Dclojure.compiler.direct-linking=true \ - "-H:IncludeResources=BABASHKA_VERSION" \ - "-H:IncludeResources=SCI_VERSION" \ - -H:ReflectionConfigurationFiles=reflection.json \ - --initialize-at-run-time=java.lang.Math\$RandomNumberGeneratorHolder \ - --initialize-at-build-time \ - -H:Log=registerResource: \ - -H:EnableURLProtocols=http,https \ - --enable-all-security-services \ - -H:+JNI \ - --verbose \ - --no-fallback \ - --no-server \ - "$BABASHKA_XMX" +args=( -jar target/babashka-$BABASHKA_VERSION-standalone.jar \ + -H:Name=bb \ + -H:+ReportExceptionStackTraces \ + -J-Dclojure.spec.skip-macros=true \ + -J-Dclojure.compiler.direct-linking=true \ + "-H:IncludeResources=BABASHKA_VERSION" \ + "-H:IncludeResources=SCI_VERSION" \ + -H:ReflectionConfigurationFiles=reflection.json \ + --initialize-at-run-time=java.lang.Math\$RandomNumberGeneratorHolder \ + --initialize-at-build-time \ + -H:Log=registerResource: \ + -H:EnableURLProtocols=http,https \ + --enable-all-security-services \ + -H:+JNI \ + --verbose \ + --no-fallback \ + --no-server \ + "$BABASHKA_XMX" ) + +if [ "$BABASHKA_STATIC" = "true" ]; then + args+=("--static") +fi + +$GRAALVM_HOME/bin/native-image "${args[@]}" lein clean From 6f6e42ad2f601b5a672f6d1aa73d04e9ad3cc72d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 12:05:06 +0100 Subject: [PATCH 003/264] v0.0.72 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 75b9c2a8..79429ec0 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.72-SNAPSHOT \ No newline at end of file +0.0.72 \ No newline at end of file From 2024d0945560fee68aa11eabd1a50c179ec686ff Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 12:23:23 +0100 Subject: [PATCH 004/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index cf9f1739..79429ec0 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.71 \ No newline at end of file +0.0.72 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 79429ec0..d323803a 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.72 \ No newline at end of file +0.0.73-SNAPSHOT \ No newline at end of file From 761e7995f7eee7296d12a43de8aa9ea3dd3061c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahu=CE=BB=20D=C3=A9?= Date: Sun, 23 Feb 2020 21:26:45 +0100 Subject: [PATCH 005/264] Improve Dockerfile, add .dockerignore (#273) --- .dockerignore | 18 ++++++++++++++++++ Dockerfile | 15 +++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..eefa27e4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +.circleci/ +.git/ +.clj-kondo/ +.github/ +doc/ +examples/ +logo/ +test-resources/ +test/ +.gitignore +.carve_ignore +.gitmodules +appveyor.yml +CHANGES.md +deps.edn +Dockerfile +LICENSE +README.md diff --git a/Dockerfile b/Dockerfile index 267c3304..d4223452 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,19 @@ -FROM ubuntu AS BASE +FROM clojure:lein-2.9.1 AS BASE -RUN apt-get update -RUN apt-get install -yy curl unzip build-essential zlib1g-dev +RUN apt update +RUN apt install --no-install-recommends -yy curl unzip build-essential zlib1g-dev WORKDIR "/opt" RUN curl -sLO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz RUN tar -xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz ENV GRAALVM_HOME="/opt/graalvm-ce-java8-19.3.1" ENV JAVA_HOME="/opt/graalvm-ce-java8-19.3.1/bin" ENV PATH="$PATH:$JAVA_HOME" +ENV BABASHKA_STATIC="true" COPY . . -RUN apt install -y sudo -RUN ./.circleci/script/install-leiningen RUN ./script/compile -RUN cp bb /usr/local/bin -FROM ubuntu:bionic -COPY --from=BASE /usr/local/bin/bb /usr/local/bin +FROM scratch + +COPY --from=BASE /opt/bb /bin/bb CMD ["bb"] From 2285c92e9926bc17ac0a5ba818dc5066000c47f8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 22:05:00 +0100 Subject: [PATCH 006/264] Add linux static build step --- .circleci/config.yml | 87 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f306e408..c86cb6af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,6 +70,74 @@ jobs: GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0 BABASHKA_PLATFORM: linux # used in release script BABASHKA_TEST_ENV: native + steps: + - checkout + - run: + name: "Pull Submodules" + command: | + git submodule init + git submodule update + - restore_cache: + keys: + - linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }} + - run: + name: Install Clojure + command: | + wget https://download.clojure.org/install/linux-install-1.10.1.447.sh + chmod +x linux-install-1.10.1.447.sh + sudo ./linux-install-1.10.1.447.sh + - run: + name: Install lsof + command: | + sudo apt-get install lsof + - run: + name: Install native dev tools + command: | + sudo apt-get update + sudo apt-get -y install gcc g++ zlib1g-dev + - run: + name: Download GraalVM + command: | + cd ~ + if ! [ -d graalvm-ce-java8-19.3.0 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-linux-amd64-19.3.0.tar.gz + tar xzf graalvm-ce-java8-linux-amd64-19.3.0.tar.gz + fi + - run: + name: Build binary + command: | + script/compile + no_output_timeout: 30m + - run: + name: Run tests + command: | + script/test + script/run_lib_tests + - run: + name: Release + command: | + .circleci/script/release + - save_cache: + paths: + - ~/.m2 + - ~/graalvm-ce-java8-19.3.0 + key: linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }} + - store_artifacts: + path: /tmp/release + destination: release + - run: + name: Publish artifact link to Slack + command: | + ./bb .circleci/script/publish_artifact.clj + linux-static: + docker: + - image: circleci/clojure:lein-2.8.1 + working_directory: ~/repo + environment: + LEIN_ROOT: "true" + GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0 + BABASHKA_PLATFORM: linux-static # used in release script + BABASHKA_TEST_ENV: native BABASHKA_STATIC: true steps: - checkout @@ -104,10 +172,6 @@ jobs: curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-linux-amd64-19.3.0.tar.gz tar xzf graalvm-ce-java8-linux-amd64-19.3.0.tar.gz fi - # - run: - # name: Install GraalVM SSL libs - # command: | - # .circleci/script/graalvm_ssl - run: name: Build binary command: | @@ -118,10 +182,6 @@ jobs: command: | script/test script/run_lib_tests - # - run: - # name: Performance report - # command: | - # .circleci/script/performance - run: name: Release command: | @@ -172,10 +232,6 @@ jobs: curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-darwin-amd64-19.3.0.tar.gz tar xzf graalvm-ce-java8-darwin-amd64-19.3.0.tar.gz fi - # - run: - # name: Install GraalVM SSL libs - # command: | - # .circleci/script/graalvm_ssl - run: name: Build binary command: | @@ -186,10 +242,6 @@ jobs: command: | script/test script/run_lib_tests - # - run: - # name: Performance report - # command: | - # .circleci/script/performance - run: name: Release command: | @@ -250,6 +302,7 @@ workflows: jobs: - jvm - linux + - linux-static - mac - deploy: filters: @@ -258,6 +311,7 @@ workflows: requires: - jvm - linux + - linux-static - mac - docker: filters: @@ -266,4 +320,5 @@ workflows: requires: - jvm - linux + - linux-static - mac From f4ab59831d7b8cdbea183e62091bc69d76400179 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 22:16:10 +0100 Subject: [PATCH 007/264] v0.0.73 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d323803a..93323757 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.73-SNAPSHOT \ No newline at end of file +0.0.73 \ No newline at end of file From f80542627b844215a27048e9183f642ec2f41ab0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 22:51:22 +0100 Subject: [PATCH 008/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 79429ec0..93323757 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.72 \ No newline at end of file +0.0.73 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 93323757..dcb8e4c2 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.73 \ No newline at end of file +0.0.74-SNAPSHOT \ No newline at end of file From 91ffd380748e39e02789c5c03ddc26e77416681d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 22:56:47 +0100 Subject: [PATCH 009/264] README: static binary --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 00c3e269..c133f2da 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,9 @@ $ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/inst ### Download -You may also download a binary from [Github](https://github.com/borkdude/babashka/releases). +You may also download a binary from +[Github](https://github.com/borkdude/babashka/releases). For linux there is a +static binary available which can be used on Alpine. ## Usage From db32d61d6032bff0ac2d07cf3cde02d02012e2e8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 23 Feb 2020 23:20:16 +0100 Subject: [PATCH 010/264] Add thank yous --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c133f2da..c2069ffa 100644 --- a/README.md +++ b/README.md @@ -965,6 +965,9 @@ clojure.core/ffirst ## Thanks - [adgoji](https://www.adgoji.com/) for financial support +- [Nikita Prokopov](https://github.com/tonsky) for the logo +- [contributors](https://github.com/borkdude/babashka/graphs/contributors) and + other users posting issues with bug reports and ideas ## License From b744efd60b5e0509365c3eaba0bec08015c6e9fb Mon Sep 17 00:00:00 2001 From: sogaiu <33044872+sogaiu@users.noreply.github.com> Date: Tue, 25 Feb 2020 09:17:22 +0000 Subject: [PATCH 011/264] Support doc for slurp and spit (#276) --- src/babashka/impl/clojure/core.clj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index bb7502af..c1295d13 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -1,7 +1,8 @@ (ns babashka.impl.clojure.core {:no-doc true} (:refer-clojure :exclude [future]) - (:require [borkdude.graal.locking :as locking])) + (:require [borkdude.graal.locking :as locking] + [sci.impl.namespaces :refer [copy-core-var]])) (defn locking* [form bindings v f & args] (apply @#'locking/locking form bindings v f args)) @@ -25,8 +26,8 @@ 'deliver deliver 'locking (with-meta locking* {:sci/macro true}) 'shutdown-agents shutdown-agents - 'slurp slurp - 'spit spit + 'slurp (copy-core-var slurp) + 'spit (copy-core-var spit) 'time (with-meta time* {:sci/macro true}) 'Throwable->map Throwable->map 'compare-and-set! compare-and-set!}) From bdd65aa6fe9dbbb661012c638b41b4ba518bf27b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 26 Feb 2020 09:42:07 +0100 Subject: [PATCH 012/264] sci: add re-matcher --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index eebb4566..07a72ce0 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit eebb456628beb2ac0d1e31c2be46ee0683b9ee7a +Subproject commit 07a72ce0b3cd7029d682f19c0edbba0901ad78cb From 42b2c924d3b0a1f6855fbb7c323ea97536d695bd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 26 Feb 2020 09:54:49 +0100 Subject: [PATCH 013/264] sci: add re-groups --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 07a72ce0..fca022bc 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 07a72ce0b3cd7029d682f19c0edbba0901ad78cb +Subproject commit fca022bc4450162d355a8e5e9a5dafe531ad9009 From 7ef2cd3dc4e358d7f5a9aefa7f6f235cc131a3cf Mon Sep 17 00:00:00 2001 From: sogaiu <33044872+sogaiu@users.noreply.github.com> Date: Wed, 26 Feb 2020 19:27:35 +0000 Subject: [PATCH 014/264] Support doc for file-seq (#277) --- src/babashka/impl/clojure/core.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index c1295d13..7374e837 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -17,7 +17,7 @@ ret#)) (def core-extras - {'file-seq file-seq + {'file-seq (copy-core-var file-seq) 'agent agent 'instance? instance? ;; TODO: move to sci 'send send From 6bb2b530e1f320f7250620bbcb560a530b67624a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 28 Feb 2020 09:59:32 +0100 Subject: [PATCH 015/264] sci: docs --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index fca022bc..82d01820 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit fca022bc4450162d355a8e5e9a5dafe531ad9009 +Subproject commit 82d018207148a77fc53beeb386bc32b0009e8a31 From 92e5c4a432747bc870dbc69cb7bc5a3d50617996 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 28 Feb 2020 18:08:05 +0100 Subject: [PATCH 016/264] Base Docker image on busybox, at least it has cat and tail --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d4223452..8de22c80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,8 @@ COPY . . RUN ./script/compile -FROM scratch +FROM busybox:musl -COPY --from=BASE /opt/bb /bin/bb +RUN mkdir -p /usr/local/bin +COPY --from=BASE /opt/bb /usr/local/bin/bb CMD ["bb"] From 94559f7626d7e0e8adda2d5627be846c9371a3d0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 29 Feb 2020 09:22:22 +0100 Subject: [PATCH 017/264] Add HTTP docs --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index c2069ffa..b29f20e3 100644 --- a/README.md +++ b/README.md @@ -622,6 +622,32 @@ bb ' process 2 ``` +## HTTP + +For making HTTP requests you can use: + +- `slurp` for simple `GET` requests +- [clj-http-lite](https://github.com/borkdude/clj-http-lite) as a library +- `curl` via `clojure.java.shell`. For an example, see the following + subsection. + +### HTTP over Unix sockets + +This can be useful for talking to Docker: + +``` clojure +(require '[clojure.java.shell :refer [sh]]) +(require '[cheshire.core :as json]) +(-> (sh "curl" "--silent" + "--no-buffer" "--unix-socket" + "/var/run/docker.sock" + "http://localhost/images/json") + :out + (json/parse-string true) + first + :RepoTags) ;;=> ["borkdude/babashka:latest"] +``` + ## Differences with Clojure Babashka is implemented using the [Small Clojure From 8328a14183abd01bb2a2d21ae6d93a46e0565ee2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 29 Feb 2020 10:31:46 +0100 Subject: [PATCH 018/264] Wipe CirleCI cache --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c86cb6af..6392c164 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: jvm: - docker: + docker: # specify the version you desire here - image: circleci/clojure:lein-2.8.1 working_directory: ~/repo From 6e11b7c0bc75676f7ec6aede20ade8769aa55b1b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 29 Feb 2020 13:24:16 +0100 Subject: [PATCH 019/264] Install older version of lein --- .circleci/config.yml | 2 +- .circleci/script/install-leiningen | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6392c164..c86cb6af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: jvm: - docker: + docker: # specify the version you desire here - image: circleci/clojure:lein-2.8.1 working_directory: ~/repo diff --git a/.circleci/script/install-leiningen b/.circleci/script/install-leiningen index ff5f8235..5454833d 100755 --- a/.circleci/script/install-leiningen +++ b/.circleci/script/install-leiningen @@ -1,6 +1,7 @@ #!/usr/bin/env bash -curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > lein +cd /tmp +git clone https://github.com/technomancy/leiningen/tree/f3864bc35d8280a8461b7f6c593b1919a75bef7f sudo mkdir -p /usr/local/bin/ -sudo mv lein /usr/local/bin/lein -sudo chmod a+x /usr/local/bin/lein +cp leiningen/bin/lein /usr/local/bin +chmod a+x /usr/local/bin/lein From 1085e2591d09d3e989d970aa0ade02d726721a13 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 29 Feb 2020 13:33:50 +0100 Subject: [PATCH 020/264] Fix lein install on CircleCI --- .circleci/script/install-leiningen | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.circleci/script/install-leiningen b/.circleci/script/install-leiningen index 5454833d..f34e3322 100755 --- a/.circleci/script/install-leiningen +++ b/.circleci/script/install-leiningen @@ -1,7 +1,6 @@ #!/usr/bin/env bash -cd /tmp -git clone https://github.com/technomancy/leiningen/tree/f3864bc35d8280a8461b7f6c593b1919a75bef7f +curl https://raw.githubusercontent.com/technomancy/leiningen/2.9.1/bin/lein-pkg > lein sudo mkdir -p /usr/local/bin/ -cp leiningen/bin/lein /usr/local/bin -chmod a+x /usr/local/bin/lein +sudo mv lein /usr/local/bin/lein +sudo chmod a+x /usr/local/bin/lein From 6b93135ee26b5171bf33cd680bd0870aaa8ebfeb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 29 Feb 2020 13:37:02 +0100 Subject: [PATCH 021/264] Fix lein on CircleCI Mac --- .circleci/script/install-leiningen | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/script/install-leiningen b/.circleci/script/install-leiningen index f34e3322..fc4b11ea 100755 --- a/.circleci/script/install-leiningen +++ b/.circleci/script/install-leiningen @@ -1,6 +1,6 @@ #!/usr/bin/env bash -curl https://raw.githubusercontent.com/technomancy/leiningen/2.9.1/bin/lein-pkg > lein +curl https://raw.githubusercontent.com/technomancy/leiningen/2.9.1/bin/lein > lein sudo mkdir -p /usr/local/bin/ sudo mv lein /usr/local/bin/lein sudo chmod a+x /usr/local/bin/lein From 00420879beffa182ac1e1a7990bc238b267f2d24 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 12:06:19 +0100 Subject: [PATCH 022/264] Update README --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b29f20e3..2ace199b 100644 --- a/README.md +++ b/README.md @@ -865,13 +865,18 @@ $ < /tmp/test.txt bb -io '(shuffle *input*)' ### Fetch latest Github release tag -For converting JSON to EDN, see [jet](https://github.com/borkdude/jet). +``` shell +(require '[clojure.java.shell :refer [sh]] + '[cheshire.core :as json]) -``` shellsession -$ curl -s https://api.github.com/repos/borkdude/babashka/tags | -jet --from json --keywordize --to edn | -bb '(-> *input* first :name (subs 1))' -"0.0.4" +(defn babashka-latest-version [] + (-> (sh "curl" "https://api.github.com/repos/borkdude/babashka/tags") + :out + (json/parse-string true) + first + :name)) + +(babashka-latest-version) ;;=> "v0.0.73" ``` ### Generate deps.edn entry for a gitlib From 24a469af656c3fc229b0e746f577babff853ba75 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 16:27:35 +0100 Subject: [PATCH 023/264] [#255] support clojure.core.async/go macro by falling back on threads --- src/babashka/impl/async.clj | 44 +++++++++++++++++++++++++++++++++--- test/babashka/async_test.clj | 35 ++++++++++++++++++++++++++++ test/babashka/main_test.clj | 9 -------- 3 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 test/babashka/async_test.clj diff --git a/src/babashka/impl/async.clj b/src/babashka/impl/async.clj index 9cfa421a..6d2cf7a0 100644 --- a/src/babashka/impl/async.clj +++ b/src/babashka/impl/async.clj @@ -1,18 +1,50 @@ (ns babashka.impl.async {:no-doc true} (:require [clojure.core.async :as async] - [clojure.core.async.impl.protocols :as protocols])) + [clojure.core.async.impl.protocols :as protocols] + [sci.impl.vars :as vars])) + +(def ^java.util.concurrent.Executor executor @#'async/thread-macro-executor) + +(defn thread-call + "Executes f in another 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 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 alt!! + "Like alt!, except as if by alts!!, will block until completed, and + not intended for use in (go ...) blocks." + [_ _ & clauses] + (async/do-alt 'clojure.core.async/alts!! clauses)) + +(defn go-loop + [_ _ bindings & body] + (list 'clojure.core.async/thread (list* 'loop bindings body))) + (def async-namespace {'!! async/>!! 'admix async/admix 'alts! async/alts! 'alts!! async/alts!! + 'alt!! (with-meta alt!! {:sci/macro true}) 'buffer async/buffer 'chan async/chan 'close! async/close! @@ -53,7 +85,7 @@ 'take! async/take! 'tap async/tap 'thread (with-meta thread {:sci/macro true}) - 'thread-call async/thread-call + 'thread-call thread-call 'timeout async/timeout 'to-chan async/to-chan 'toggle async/toggle @@ -65,7 +97,13 @@ 'unsub async/unsub 'unsub-all async/unsub-all 'untap async/untap - 'untap-all async/untap-all}) + 'untap-all async/untap-all + ;; polyfill + 'go (with-meta thread {:sci/macro true}) + '! async/>!! + 'alt! (with-meta alt!! {:sci/macro true}) + 'go-loop (with-meta go-loop {:sci/macro true})}) (def async-protocols-namespace {'ReadPort protocols/ReadPort}) diff --git a/test/babashka/async_test.clj b/test/babashka/async_test.clj new file mode 100644 index 00000000..783e7788 --- /dev/null +++ b/test/babashka/async_test.clj @@ -0,0 +1,35 @@ +(ns babashka.async-test + (:require + [babashka.test-utils :as test-utils] + [clojure.edn :as edn] + [clojure.test :as t :refer [deftest is]])) + +(deftest alts!!-test + (is (= "process 2\n" (test-utils/bb nil " + (defn async-command [& args] + (async/thread (apply shell/sh \"bash\" \"-c\" args))) + + (-> (async/alts!! [(async-command \"sleep 2 && echo process 1\") + (async-command \"sleep 1 && echo process 2\")]) + first :out str/trim println)")))) + +(deftest go-test + (is (number? (edn/read-string (test-utils/bb nil " +(defn calculation-go [] + (async/go + ;; wait for some stuff + (rand-int 1000))) + +(defn get-result-go [] + (async/go + (->> + (repeatedly 10 calculation-go) + (map async/ (async/alts!! [(async-command \"sleep 2 && echo process 1\") - (async-command \"sleep 1 && echo process 2\")]) - first :out str/trim println)")))) - (deftest tools-cli-test (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb")))) From 1a5100ad323c78628861ebb080f3e43b7be9afbf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 16:56:28 +0100 Subject: [PATCH 024/264] Async docs --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2ace199b..5cd06bb8 100644 --- a/README.md +++ b/README.md @@ -186,8 +186,7 @@ enumerated explicitly. `make-parents`, `output-stream`, `reader`, `resource`, `writer` - `clojure.main`: `repl` - [`clojure.core.async`](https://clojure.github.io/core.async/) aliased as - `async`. The `alt` and `go` macros are not available but `alts!!` does work as - it is a function. + `async`. - `clojure.stacktrace` - `clojure.test` - `clojure.pprint`: `pprint` (currently backed by [fipp](https://github.com/brandonbloom/fipp)'s `fipp.edn/pprint`) @@ -606,10 +605,10 @@ Also see this [example](examples/process_builder.clj). ## Async -Apart from `future` and `pmap` for creating threads, you may use the `async` -namespace, which maps to `clojure.core.async`, for asynchronous scripting. The -following example shows how to get first available value from two different -processes: +Apart from `future` and `pmap` for creating threads, you may use the +`clojure.core.async` namespace, aliases as `async`, for asynchronous +scripting. The following example shows how to get first available value from two +different processes: ``` clojure bb ' @@ -622,6 +621,11 @@ bb ' process 2 ``` +Note: the `go` macro is available for compatibility with JVM programs, but the +implementation maps to `clojure.core.async/thread` and the single exclamation +mark operations (`!`, etc.) map to with the double exclamation mark +operations (`!!`, etc.). It will not `park` threads, like on the JVM. + ## HTTP For making HTTP requests you can use: From 2a49f61168c482dff3448e7bdccb2878c277bd29 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 17:19:43 +0100 Subject: [PATCH 025/264] Fix [#280] --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 82d01820..b6a91fa0 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 82d018207148a77fc53beeb386bc32b0009e8a31 +Subproject commit b6a91fa0ecc2d5fbae869f878b5a218dc3eb20ce From 6fe7972952f2127e4c46fdab9a65fa057d76e26d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 17:41:02 +0100 Subject: [PATCH 026/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index b6a91fa0..51a6f358 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit b6a91fa0ecc2d5fbae869f878b5a218dc3eb20ce +Subproject commit 51a6f358f1e1e18048e7138c80b8896f50cab6ee From fc3a229c65e550ab42bec515f787ab6a2511040b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 17:43:10 +0100 Subject: [PATCH 027/264] README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5cd06bb8..409a78fd 100644 --- a/README.md +++ b/README.md @@ -606,7 +606,7 @@ Also see this [example](examples/process_builder.clj). ## Async Apart from `future` and `pmap` for creating threads, you may use the -`clojure.core.async` namespace, aliases as `async`, for asynchronous +`clojure.core.async` namespace for asynchronous scripting. The following example shows how to get first available value from two different processes: @@ -623,8 +623,8 @@ process 2 Note: the `go` macro is available for compatibility with JVM programs, but the implementation maps to `clojure.core.async/thread` and the single exclamation -mark operations (`!`, etc.) map to with the double exclamation mark -operations (`!!`, etc.). It will not `park` threads, like on the JVM. +mark operations (`!`, etc.) map to the double exclamation mark operations +(`!!`, etc.). It will not `park` threads, like on the JVM. ## HTTP From 30280ad0a863819ec0f8f507c949d72528916041 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 19:43:39 +0100 Subject: [PATCH 028/264] v0.0.74 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index dcb8e4c2..05389a0e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.74-SNAPSHOT \ No newline at end of file +0.0.74 \ No newline at end of file From 167349981e439999ddc0b48d03fbc387811cd559 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 19:57:17 +0100 Subject: [PATCH 029/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 93323757..05389a0e 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.73 \ No newline at end of file +0.0.74 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 05389a0e..5a4e5b73 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.74 \ No newline at end of file +0.0.75-SNAPSHOT \ No newline at end of file From 7ba228a32b7c273962f1bc7f543f605f4222a836 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 1 Mar 2020 22:45:55 +0100 Subject: [PATCH 030/264] Doc tweak --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 409a78fd..3e58d0f8 100644 --- a/README.md +++ b/README.md @@ -605,10 +605,9 @@ Also see this [example](examples/process_builder.clj). ## Async -Apart from `future` and `pmap` for creating threads, you may use the -`clojure.core.async` namespace for asynchronous -scripting. The following example shows how to get first available value from two -different processes: +In addition to `future`, `pmap`, `promise` and friends, you may use the +`clojure.core.async` namespace for asynchronous scripting. The following example +shows how to get first available value from two different processes: ``` clojure bb ' @@ -624,7 +623,7 @@ process 2 Note: the `go` macro is available for compatibility with JVM programs, but the implementation maps to `clojure.core.async/thread` and the single exclamation mark operations (`!`, etc.) map to the double exclamation mark operations -(`!!`, etc.). It will not `park` threads, like on the JVM. +(`!!`, etc.). It will not "park" threads, like on the JVM. ## HTTP From 6d9b2d0042d26e16ee16c2abce90a29835bbfd64 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 09:50:47 +0100 Subject: [PATCH 031/264] Update goals --- README.md | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3e58d0f8..3303e285 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ bb took 4ms. ## Rationale -The sweet spot for babashka is executing Clojure snippets or scripts in the same -space where you would use Bash. +The sweet spot for babashka is executing Clojure expressions or scripts in the +same space where you would use Bash. As one user described it: @@ -34,21 +34,27 @@ As one user described it: Goals: -* Fast startup / low latency. This is achieved by compiling to native using [GraalVM](https://github.com/oracle/graal). -* Familiarity and portability. Keep migration barriers between bash and Clojure as low as possible by: - - Gradually introducing Clojure expressions to existing bash scripts - - Scripts written in babashka should also be able to run on the JVM without major changes. -* Multi-threading support similar to Clojure on the JVM -* Batteries included (clojure.tools.cli, core.async, ...) +* Low latency Clojure scripting alternative to JVM Clojure. +* Easy installation: grab the self-contained binary and run! No JVM needed. +* Familiarity and portability: + - Scripts should be compatible with JVM Clojure as much as possible + - Scripts should be platform-independent as much as possible. +* Allow interop with commonly used classes like `java.io.File` and `System` +* Multi-threading support (`pmap`, `future`, `core.async`) +* Batteries included (tools.cli, cheshire, ...) +* Library support via popular tools like the `clojure` CLI Non-goals: -* Performance -* Provide a mixed Clojure/bash DSL (see portability). +* Performance1 +* Provide a mixed Clojure/Bash DSL (see portability). * Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. -Babashka uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci -implements a subset of Clojure and is not as performant as compiled code. If your script is taking more than a few seconds, Clojure on the JVM may be a better fit. +1 Babashka uses [sci](https://github.com/borkdude/sci) for interpreting +Clojure. Sci implements a suffiently large subset of Clojure. Interpreting code +is in general not as performant as executing compiled code. If your script takes +more than a few seconds to run, Clojure on the JVM may be a better fit, since +the startup time penalty of Clojure on the JVM outweighs its performance. Read more about the differences with Clojure [here](#differences-with-clojure). @@ -656,23 +662,20 @@ This can be useful for talking to Docker: Babashka is implemented using the [Small Clojure Interpreter](https://github.com/borkdude/sci). This means that a snippet or script is not compiled to JVM bytecode, but executed form by form by a runtime -which implements a subset of Clojure. Babashka is compiled to a native binary -using [GraalVM](https://github.com/oracle/graal). It comes with a selection of -built-in namespaces and functions from Clojure and other useful libraries. The -data types (numbers, strings, persistent collections) are the +which implements a sufficiently large subset of Clojure. Babashka is compiled to +a native binary using [GraalVM](https://github.com/oracle/graal). It comes with +a selection of built-in namespaces and functions from Clojure and other useful +libraries. The data types (numbers, strings, persistent collections) are the same. Multi-threading is supported (`pmap`, `future`). Differences with Clojure: -- A subset of Java classes are supported. - -- Only the `clojure.core`, `clojure.edn`, `clojue.java.io`, - `clojure.java.shell`, `clojure.set`, `clojure.stacktrace`, `clojure.string`, - `clojure.template`, `clojure.test` and `clojure.walk` namespaces are available - from Clojure. +- A pre-selected set of Java classes are supported. You cannot add Java classes + at runtime. - Interpretation comes with overhead. Therefore tight loops are likely slower - than in Clojure on the JVM. + than in Clojure on the JVM. In general interpretation yields slower programs + than compiled programs. - No support for unboxed types. From b55d5c230138146652e3883e8a304c8f2c375709 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 09:55:50 +0100 Subject: [PATCH 032/264] README --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3303e285..46091d9f 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,11 @@ As one user described it: Goals: * Low latency Clojure scripting alternative to JVM Clojure. -* Easy installation: grab the self-contained binary and run! No JVM needed. +* Easy installation: grab the self-contained binary and run. No JVM needed. * Familiarity and portability: - Scripts should be compatible with JVM Clojure as much as possible - - Scripts should be platform-independent as much as possible. + - Scripts should be platform-independent as much as possible. Babashka offers + support for linux, macOS and Windows. * Allow interop with commonly used classes like `java.io.File` and `System` * Multi-threading support (`pmap`, `future`, `core.async`) * Batteries included (tools.cli, cheshire, ...) @@ -46,18 +47,16 @@ Goals: Non-goals: -* Performance1 +* Performance. Babashka uses [sci](https://github.com/borkdude/sci) for +interpreting Clojure. Sci implements a suffiently large subset of +Clojure. Interpreting code is in general not as performant as executing compiled +code. If your script takes more than a few seconds to run, Clojure on the JVM +may be a better fit, since the startup time penalty of Clojure on the JVM +outweighs its performance. Read more about the differences with Clojure +[here](#differences-with-clojure). * Provide a mixed Clojure/Bash DSL (see portability). * Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. -1 Babashka uses [sci](https://github.com/borkdude/sci) for interpreting -Clojure. Sci implements a suffiently large subset of Clojure. Interpreting code -is in general not as performant as executing compiled code. If your script takes -more than a few seconds to run, Clojure on the JVM may be a better fit, since -the startup time penalty of Clojure on the JVM outweighs its performance. - -Read more about the differences with Clojure [here](#differences-with-clojure). - ## Status Experimental. Breaking changes are expected to happen at this phase. Keep an eye From 1b20fb1dcbb6b0d2bebe74e250ce1fb42c306fe7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 09:56:22 +0100 Subject: [PATCH 033/264] README --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 46091d9f..b026a07e 100644 --- a/README.md +++ b/README.md @@ -47,15 +47,17 @@ Goals: Non-goals: -* Performance. Babashka uses [sci](https://github.com/borkdude/sci) for +* Performance1 +* Provide a mixed Clojure/Bash DSL (see portability). +* Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. + +1 Babashka uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci implements a suffiently large subset of Clojure. Interpreting code is in general not as performant as executing compiled code. If your script takes more than a few seconds to run, Clojure on the JVM may be a better fit, since the startup time penalty of Clojure on the JVM outweighs its performance. Read more about the differences with Clojure [here](#differences-with-clojure). -* Provide a mixed Clojure/Bash DSL (see portability). -* Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. ## Status From c4a44aa7e61bc88ac2f4154f31af1e1806f4c133 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 09:57:24 +0100 Subject: [PATCH 034/264] README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b026a07e..a1106a15 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ Non-goals: interpreting Clojure. Sci implements a suffiently large subset of Clojure. Interpreting code is in general not as performant as executing compiled code. If your script takes more than a few seconds to run, Clojure on the JVM -may be a better fit, since the startup time penalty of Clojure on the JVM -outweighs its performance. Read more about the differences with Clojure +may be a better fit, since the performance of Clojure on the JVM outweighs its +startup time penalty. Read more about the differences with Clojure [here](#differences-with-clojure). ## Status From 4c642140929005564dea12206086484a35494486 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 10:00:28 +0100 Subject: [PATCH 035/264] README --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a1106a15..f75ab1a7 100644 --- a/README.md +++ b/README.md @@ -14,17 +14,6 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas @laheadle on Clojurians Slack -## Quickstart - -``` shellsession -$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install) -$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' -("doc" "resources" "sci" "script" "src" "target" "test") -bb took 4ms. -``` - -## Rationale - The sweet spot for babashka is executing Clojure expressions or scripts in the same space where you would use Bash. @@ -59,6 +48,15 @@ may be a better fit, since the performance of Clojure on the JVM outweighs its startup time penalty. Read more about the differences with Clojure [here](#differences-with-clojure). +## Quickstart + +``` shellsession +$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install) +$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' +("doc" "resources" "sci" "script" "src" "target" "test") +bb took 4ms. +``` + ## Status Experimental. Breaking changes are expected to happen at this phase. Keep an eye From 1aa1abf2929635e0c435e6ea8baab88af89a7b98 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 10:01:04 +0100 Subject: [PATCH 036/264] README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f75ab1a7..5775e3d9 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ As one user described it: > I’m quite at home in Bash most of the time, but there’s a substantial grey area of things that are too complicated to be simple in bash, but too simple to be worth writing a clj/s script for. Babashka really seems to hit the sweet spot for those cases. -Goals: +## Goals * Low latency Clojure scripting alternative to JVM Clojure. * Easy installation: grab the self-contained binary and run. No JVM needed. @@ -34,7 +34,7 @@ Goals: * Batteries included (tools.cli, cheshire, ...) * Library support via popular tools like the `clojure` CLI -Non-goals: +## Non-goals * Performance1 * Provide a mixed Clojure/Bash DSL (see portability). From 5ed1994ea68a4a1e5f716a37ec47a2c75df7e3ce Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 10:02:36 +0100 Subject: [PATCH 037/264] README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5775e3d9..80ac073c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ As one user described it: * Batteries included (tools.cli, cheshire, ...) * Library support via popular tools like the `clojure` CLI +Also see the [slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020) of the Babashka talk at ClojureD 2020 (video coming soon). + ## Non-goals * Performance1 From 2fb4156d692659223909215fcb7396e7a47184d8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 13:00:50 +0100 Subject: [PATCH 038/264] Doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 80ac073c..4c45a46e 100644 --- a/README.md +++ b/README.md @@ -638,8 +638,8 @@ For making HTTP requests you can use: - `slurp` for simple `GET` requests - [clj-http-lite](https://github.com/borkdude/clj-http-lite) as a library -- `curl` via `clojure.java.shell`. For an example, see the following - subsection. +- `curl` via `clojure.java.shell`. Also see + [babashka.curl](https://github.com/borkdude/babashka.curl). ### HTTP over Unix sockets From 01aa97847b34844b9b6245a6671a43febb61bfdb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 13:18:11 +0100 Subject: [PATCH 039/264] Add babashka.curl test --- script/lib_tests/babashka_curl_test | 33 +++++++++++++++++++++++++++++ script/run_lib_tests | 1 + 2 files changed, 34 insertions(+) create mode 100755 script/lib_tests/babashka_curl_test diff --git a/script/lib_tests/babashka_curl_test b/script/lib_tests/babashka_curl_test new file mode 100755 index 00000000..ebca3831 --- /dev/null +++ b/script/lib_tests/babashka_curl_test @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -eo pipefail + +export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {babasha.curl {:git/url "https://github.com/borkdude/babashka.curl" :sha "1ec005d0c11d316bc5e6ab38e34546c75055f33b"}}}' -Spath) + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + +$BB_CMD -e " +(require '[babashka.curl :as curl]) + +(prn (subs (curl/get \"https://www.clojure.org\") 0 10)) + +(prn (subs (curl/get \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\") 0 10)) + +(prn (subs (curl/post \"https://postman-echo.com/post\") 0 10)) + +(prn (subs (curl/post \"https://postman-echo.com/post\" + {:body (json/generate-string {:a 1}) + :headers {\"X-Hasura-Role\" \"admin\"} + :content-type :json + :accept :json}) 0 10)) + +(prn (subs (curl/put \"https://postman-echo.com/put\" + {:body (json/generate-string {:a 1}) + :headers {\"X-Hasura-Role\" \"admin\"} + :content-type :json + :accept :json}) 0 10)) +" diff --git a/script/run_lib_tests b/script/run_lib_tests index 8e0695a9..87e152be 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -8,3 +8,4 @@ script/lib_tests/spartan_spec_test script/lib_tests/clojure_csv_test script/lib_tests/regal_test script/lib_tests/medley_test +script/lib_tests/babashka_curl_test From fa1bb35ee4e794dfd6acaae9945a47bd5487656f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 13:49:23 +0100 Subject: [PATCH 040/264] Update status --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c45a46e..4f4163fe 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,10 @@ bb took 4ms. ## Status -Experimental. Breaking changes are expected to happen at this phase. Keep an eye -on [CHANGES.md](CHANGES.md) for a list of breaking changes. +Functionality regarding `clojure.core` and `java.lang` can be considered stable +and is unlikely to change. Changes may happen in other parts of babashka, +although we will try our best to prevent them. Keep an eye on +[CHANGES.md](CHANGES.md) for a list of breaking changes. ## Examples From b67e364145eddf47c90f6e6458f331537ba406e4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 13:52:36 +0100 Subject: [PATCH 041/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f4163fe..471d5cfb 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ bb took 4ms. Functionality regarding `clojure.core` and `java.lang` can be considered stable and is unlikely to change. Changes may happen in other parts of babashka, although we will try our best to prevent them. Keep an eye on -[CHANGES.md](CHANGES.md) for a list of breaking changes. +[CHANGES.md](CHANGES.md) before upgrading. ## Examples From ae6d0bcda6c1c7621f6173742b435000413b5256 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 13:53:28 +0100 Subject: [PATCH 042/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 471d5cfb..1225207e 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ bb took 4ms. Functionality regarding `clojure.core` and `java.lang` can be considered stable and is unlikely to change. Changes may happen in other parts of babashka, -although we will try our best to prevent them. Keep an eye on +although we will try our best to prevent them. Always check the release notes or [CHANGES.md](CHANGES.md) before upgrading. ## Examples From a81b7a9737c0862b950b2a041108fbb168ff0f6a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 14:05:32 +0100 Subject: [PATCH 043/264] Add reflection script --- script/reflection.clj | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 script/reflection.clj diff --git a/script/reflection.clj b/script/reflection.clj new file mode 100755 index 00000000..56a1f21a --- /dev/null +++ b/script/reflection.clj @@ -0,0 +1,6 @@ +#!/usr/bin/env bb + +(require '[clojure.java.io :as io] '[clojure.string :as str] '[clojure.java.shell :refer [sh]]) +(def version (str/trim (slurp (io/file "resources" "BABASHKA_VERSION")))) +(sh "lein" "with-profiles" "+reflection" "run") +(io/copy (io/file "reflection.json") (io/file (str "babashka-" version "-reflection.json"))) From b1c81c72ed9533bab2e8645cea51d6ec1af589e1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 14:19:21 +0100 Subject: [PATCH 044/264] README --- README.md | 71 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 1225207e..d5f42e2b 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,46 @@ $ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' bb took 4ms. ``` +## Examples + +Read the output from a shell command as a lazy seq of strings: + +``` shell +$ ls | bb -i '(take 2 *input*)' +("CHANGES.md" "Dockerfile") +``` + +Read EDN from stdin and write the result to stdout: + +``` shell +$ bb '(vec (dedupe *input*))' <<< '[1 1 1 1 2]' +[1 2] +``` + +Read more about input and output flags +[here](https://github.com/borkdude/babashka/#input-and-output-flags). + +Execute a script. E.g. print the current time in California using the +`java.time` API: + +File `pst.clj`: +``` clojure +#!/usr/bin/env bb + +(def now (java.time.ZonedDateTime/now)) +(def LA-timezone (java.time.ZoneId/of "America/Los_Angeles")) +(def LA-time (.withZoneSameInstant now LA-timezone)) +(def pattern (java.time.format.DateTimeFormatter/ofPattern "HH:mm")) +(println (.format LA-time pattern)) +``` + +``` shell +$ pst.clj +05:17 +``` + +More examples can be found in the [gallery](#gallery). + ## Status Functionality regarding `clojure.core` and `java.lang` can be considered stable @@ -66,37 +106,6 @@ 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 [CHANGES.md](CHANGES.md) before upgrading. -## Examples - -``` shellsession -$ ls | bb -i '*input*' -["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "resources" "script" "src" "target" "test"] - -$ ls | bb -i '(count *input*)' -12 - -$ bb '(vec (dedupe *input*))' <<< '[1 1 1 1 2]' -[1 2] - -$ bb '(filterv :foo *input*)' <<< '[{:foo 1} {:bar 2}]' -[{:foo 1}] - -$ bb '(#(+ %1 %2 %3) 1 2 *input*)' <<< 3 -6 - -$ ls | bb -i '(filterv #(re-find #"README" %) *input*)' -["README.md"] - -$ bb '(run! #(shell/sh "touch" (str "/tmp/test/" %)) (range 100))' -$ ls /tmp/test | bb -i '*input*' -["0" "1" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "2" "20" "21" ...] - -$ bb -O '(repeat "dude")' | bb --stream '(str *input* "rino")' | bb -I '(take 3 *input*)' -("duderino" "duderino" "duderino") -``` - -More examples can be found in the [gallery](#gallery). - ## Installation ### Brew From 1f48250cfdf567fea96a82b4011d8fc1b88c5f16 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 14:19:51 +0100 Subject: [PATCH 045/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5f42e2b..b6ff4469 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ $ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' bb took 4ms. ``` -## Examples +### Examples Read the output from a shell command as a lazy seq of strings: From 3e810bc2ed9ed0bd605c9ccf87bd13ddd359a346 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 2 Mar 2020 14:21:57 +0100 Subject: [PATCH 046/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6ff4469..6c5e146f 100644 --- a/README.md +++ b/README.md @@ -1020,7 +1020,7 @@ clojure.core/ffirst ## License -Copyright © 2019 Michiel Borkent +Copyright © 2019-2020 Michiel Borkent Distributed under the EPL License. See LICENSE. From e1a705ffbab6cc8bbe4c3da0a31661700095d28e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 3 Mar 2020 11:02:45 +0100 Subject: [PATCH 047/264] Update lib test for babashka.curl --- sci | 2 +- script/lib_tests/babashka_curl_test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sci b/sci index 51a6f358..f2424029 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 51a6f358f1e1e18048e7138c80b8896f50cab6ee +Subproject commit f2424029275dac218396d9d532a8bb757aaac1db diff --git a/script/lib_tests/babashka_curl_test b/script/lib_tests/babashka_curl_test index ebca3831..7620200e 100755 --- a/script/lib_tests/babashka_curl_test +++ b/script/lib_tests/babashka_curl_test @@ -2,7 +2,7 @@ set -eo pipefail -export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {babasha.curl {:git/url "https://github.com/borkdude/babashka.curl" :sha "1ec005d0c11d316bc5e6ab38e34546c75055f33b"}}}' -Spath) +export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {babasha.curl {:git/url "https://github.com/borkdude/babashka.curl" :sha "6a4de335fa0ba75814567e013a286cafcabff8c0"}}}' -Spath) if [ "$BABASHKA_TEST_ENV" = "native" ]; then BB_CMD="./bb" From b8672a4fa7b1fa195c55a7f25714618a5a30d8c8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 3 Mar 2020 18:26:34 +0100 Subject: [PATCH 048/264] Update regal sha --- README.md | 4 ++-- script/lib_tests/regal_test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6c5e146f..a31d21bb 100644 --- a/README.md +++ b/README.md @@ -795,13 +795,13 @@ export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {clojure-csv {:mvn/version " Requires `bb` >= v0.0.71. Latest coordinates checked with with bb: ``` clojure -{:git/url "https://github.com/lambdaisland/regal" :sha "8d300f8e15f43480801766b7762530b6d412c1e6"} +{:git/url "https://github.com/lambdaisland/regal" :sha "d4e25e186f7b9705ebb3df6b21c90714d278efb7"} ``` Example: ``` shell -$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "8d300f8e15f43480801766b7762530b6d412c1e6"}}}') +$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "d4e25e186f7b9705ebb3df6b21c90714d278efb7"}}}') $ bb -e "(require '[lambdaisland.regal :as regal]) (regal/regex [:* \"ab\"])" #"(?:\Qab\E)*" diff --git a/script/lib_tests/regal_test b/script/lib_tests/regal_test index 76dcca5a..ad313fe9 100755 --- a/script/lib_tests/regal_test +++ b/script/lib_tests/regal_test @@ -2,7 +2,7 @@ set -eo pipefail -export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "8d300f8e15f43480801766b7762530b6d412c1e6"}}}' -Spath)" +export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "d4e25e186f7b9705ebb3df6b21c90714d278efb7"}}}' -Spath)" if [ "$BABASHKA_TEST_ENV" = "native" ]; then BB_CMD="./bb" From 35a2001ca885e2408fa56f659fcaa4343ef209ea Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 4 Mar 2020 20:30:36 +0100 Subject: [PATCH 049/264] ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d8a7040d..4d308908 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ pom.xml.asc !test-resources/babashka/src_for_classpath_test/foo.jar .cpcache reflection.json +/tmp +/reports From f52b208b7e92737bbfe2c465c992b3580e92838b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 4 Mar 2020 21:14:53 +0100 Subject: [PATCH 050/264] [#283] support writer arg in clojure.pprint --- src/babashka/impl/clojure/pprint.clj | 12 ++++++++++++ src/babashka/main.clj | 4 ++-- test/babashka/main_test.clj | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/babashka/impl/clojure/pprint.clj diff --git a/src/babashka/impl/clojure/pprint.clj b/src/babashka/impl/clojure/pprint.clj new file mode 100644 index 00000000..3d2a3695 --- /dev/null +++ b/src/babashka/impl/clojure/pprint.clj @@ -0,0 +1,12 @@ +(ns babashka.impl.clojure.pprint + {:no-doc true} + (:require [fipp.edn :as fipp])) + +(defn pprint + ([edn] + (fipp/pprint edn)) + ([edn writer] + (fipp/pprint edn {:writer writer}))) + +(def pprint-namespace + {'pprint pprint}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index b0b1a3a2..38f3622b 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -9,6 +9,7 @@ [babashka.impl.clojure.java.io :refer [io-namespace]] [babashka.impl.clojure.java.shell :refer [shell-namespace]] [babashka.impl.clojure.main :refer [demunge]] + [babashka.impl.clojure.pprint :refer [pprint-namespace]] [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace print-stack-trace]] [babashka.impl.common :as common] [babashka.impl.csv :as csv] @@ -21,7 +22,6 @@ [clojure.edn :as edn] [clojure.java.io :as io] [clojure.string :as str] - [fipp.edn :as fipp] [sci.addons :as addons] [sci.core :as sci] [sci.impl.interpreter :refer [eval-string*]] @@ -259,7 +259,7 @@ Everything after that is bound to *command-line-args*.")) 'clojure.repl {'demunge demunge} 'clojure.test t/clojure-test-namespace 'babashka.classpath {'add-classpath add-classpath*} - 'clojure.pprint {'pprint fipp/pprint}}) + 'clojure.pprint pprint-namespace}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index e11b0958..0ae37c5e 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -342,6 +342,10 @@ (alter-var-root #'clojure.core/inc (constantly inc2)) res)"))))) +(deftest pprint-test + (testing "writer" + (is (string? (bb nil "(let [sw (java.io.StringWriter.)] (clojure.pprint/pprint (range 10) sw) (str sw))"))))) + ;;;; Scratch (comment From ce9fbcde5036019519d7b132abc389d93f7fa426 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 5 Mar 2020 20:19:02 +0100 Subject: [PATCH 051/264] Upgrade to clojure 1.10.2-alpha1 --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index 5b67b4d9..7d1fd250 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,5 @@ {:paths ["src" "sci/src" "resources" "sci/resources"], - :deps {org.clojure/clojure {:mvn/version "1.10.1"}, + :deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}, org.clojure/tools.reader {:mvn/version "1.3.2"}, borkdude/edamame {:mvn/version "0.0.10"}, borkdude/graal.locking {:mvn/version "0.0.2"}, diff --git a/project.clj b/project.clj index 73f9cf87..528f7b9f 100644 --- a/project.clj +++ b/project.clj @@ -9,7 +9,7 @@ :url "http://opensource.org/licenses/eclipse-1.0.php"} :source-paths ["src" "sci/src"] :resource-paths ["resources" "sci/resources"] - :dependencies [[org.clojure/clojure "1.10.1"] + :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] [borkdude/edamame "0.0.10"] [borkdude/graal.locking "0.0.2"] diff --git a/sci b/sci index f2424029..8456b506 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit f2424029275dac218396d9d532a8bb757aaac1db +Subproject commit 8456b506fb8572f3199a3e0907728e346a8eec3c From e7cbc67b30787e7092a3e594b24c1b3b08cdeffe Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 5 Mar 2020 20:31:08 +0100 Subject: [PATCH 052/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 8456b506..d31b0e02 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 8456b506fb8572f3199a3e0907728e346a8eec3c +Subproject commit d31b0e02495ab052ac757e2eddb6fd581d0e47ff From 91a273034a50616e3049ec47c8b9cd013d5cac86 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 5 Mar 2020 22:01:47 +0100 Subject: [PATCH 053/264] clojure.stacktrace now works with GraalVM! --- .clj-kondo/config.edn | 2 +- src/babashka/impl/clojure/stacktrace.clj | 94 ++---------------------- src/babashka/impl/clojure/test.clj | 37 +++++----- src/babashka/main.clj | 3 +- 4 files changed, 29 insertions(+), 107 deletions(-) diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index e4db19e4..cba99996 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -4,4 +4,4 @@ babashka.impl.File/gen-wrapper-fn-2 clojure.core/def babashka.impl.Pattern/gen-wrapper-fn-2 clojure.core/def babashka.impl.Pattern/gen-constants clojure.core/declare} - :linters {:unsorted-namespaces {:level :warning}}} + :linters {:unsorted-required-namespaces {:level :warning}}} diff --git a/src/babashka/impl/clojure/stacktrace.clj b/src/babashka/impl/clojure/stacktrace.clj index 96fd9f32..4f088b16 100644 --- a/src/babashka/impl/clojure/stacktrace.clj +++ b/src/babashka/impl/clojure/stacktrace.clj @@ -1,88 +1,10 @@ -;; Copyright (c) Rich Hickey. All rights reserved. -;; The use and distribution terms for this software are covered by the -;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) -;; which can be found in the file epl-v10.html at the root of this distribution. -;; By using this software in any fashion, you are agreeing to be bound by -;; the terms of this license. -;; You must not remove this notice, or any other, from this software. - -;;; stacktrace.clj: print Clojure-centric stack traces - -;; by Stuart Sierra -;; January 6, 2009 - -(ns ^{:doc "Print stack traces oriented towards Clojure, not Java." - :author "Stuart Sierra" - :no-doc true} - babashka.impl.clojure.stacktrace) - -(set! *warn-on-reflection* true) - -(defn root-cause - "Returns the last 'cause' Throwable in a chain of Throwables." - {:added "1.1"} - [^Throwable tr] - (if-let [cause (.getCause tr)] - (recur cause) - tr)) - -(defn print-trace-element - "Prints a Clojure-oriented view of one element in a stack trace." - {:added "1.1"} - [^StackTraceElement e] - (let [class (.getClassName e) - method (.getMethodName e)] - (let [match (re-matches #"^([A-Za-z0-9_.-]+)\$(\w+)__\d+$" (str class))] - (if (and match (= "invoke" method)) - (apply printf "%s/%s" (rest match)) - (printf "%s.%s" class method)))) - (printf " (%s:%d)" (or (.getFileName e) "") (.getLineNumber e))) - -(defn print-throwable - "Prints the class and message of a Throwable. Prints the ex-data map - if present." - {:added "1.1"} - [^Throwable tr] - (printf "%s: %s" (.getName (class tr)) (.getMessage tr)) - (when-let [info (ex-data tr)] - (newline) - (pr info))) - -(defn print-stack-trace - "Prints a Clojure-oriented stack trace of tr, a Throwable. - Prints a maximum of n stack frames (default: unlimited). - Does not print chained exceptions (causes)." - {:added "1.1"} - ([tr] (print-stack-trace tr nil)) - ([^Throwable tr n] - (let [st (.getStackTrace tr)] - (print-throwable tr) - (newline) - (print " at ") - (if-let [e (first st)] - (print-trace-element e) - (print "[empty stack trace]")) - (newline) - (doseq [e (if (nil? n) - (rest st) - (take (dec n) (rest st)))] - (print " ") - (print-trace-element e) - (newline))))) - -(defn print-cause-trace - "Like print-stack-trace but prints chained exceptions (causes)." - {:added "1.1"} - ([tr] (print-cause-trace tr nil)) - ([^Throwable tr n] - (print-stack-trace tr n) - (when-let [cause (.getCause tr)] - (print "Caused by: " ) - (recur cause n)))) +(ns babashka.impl.clojure.stacktrace + {:no-doc true} + (:require [clojure.stacktrace :as stacktrace])) (def stacktrace-namespace - {'root-cause root-cause - 'print-trace-element print-trace-element - 'print-throwable print-throwable - 'print-stack-trace print-stack-trace - 'print-cause-trace print-cause-trace}) + {'root-cause stacktrace/root-cause + 'print-trace-element stacktrace/print-trace-element + 'print-throwable stacktrace/print-throwable + 'print-stack-trace stacktrace/print-stack-trace + 'print-cause-trace stacktrace/print-cause-trace}) diff --git a/src/babashka/impl/clojure/test.clj b/src/babashka/impl/clojure/test.clj index 60fcec78..97406f5d 100644 --- a/src/babashka/impl/clojure/test.clj +++ b/src/babashka/impl/clojure/test.clj @@ -1,10 +1,10 @@ - ; Copyright (c) Rich Hickey. All rights reserved. - ; The use and distribution terms for this software are covered by the - ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) - ; which can be found in the file epl-v10.html at the root of this distribution. - ; By using this software in any fashion, you are agreeing to be bound by - ; the terms of this license. - ; You must not remove this notice, or any other, from this software. +;; Copyright (c) Rich Hickey. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. ;;; test.clj: test framework for Clojure @@ -232,9 +232,8 @@ For additional event types, see the examples in the code. "} babashka.impl.clojure.test - (:require [babashka.impl.clojure.stacktrace :as stack] - [babashka.impl.common :refer [ctx]] - [clojure.string :as str] + (:require [babashka.impl.common :refer [ctx]] + [clojure.stacktrace :as stack] [clojure.template :as temp] [sci.core :as sci] [sci.impl.analyzer :as ana] @@ -430,9 +429,9 @@ result# (apply ~pred values#)] (if result# (clojure.test/do-report {:type :pass, :message ~msg, - :expected '~form, :actual (cons ~pred values#)}) + :expected '~form, :actual (cons ~pred values#)}) (clojure.test/do-report {:type :fail, :message ~msg, - :expected '~form, :actual (list '~'not (cons '~pred values#))})) + :expected '~form, :actual (list '~'not (cons '~pred values#))})) result#))) (defn assert-any @@ -443,9 +442,9 @@ `(let [value# ~form] (if value# (clojure.test/do-report {:type :pass, :message ~msg, - :expected '~form, :actual value#}) + :expected '~form, :actual value#}) (clojure.test/do-report {:type :fail, :message ~msg, - :expected '~form, :actual value#})) + :expected '~form, :actual value#})) value#)) @@ -479,9 +478,9 @@ (let [result# (instance? klass# object#)] (if result# (clojure.test/do-report {:type :pass, :message ~msg, - :expected '~form, :actual (class object#)}) + :expected '~form, :actual (class object#)}) (clojure.test/do-report {:type :fail, :message ~msg, - :expected '~form, :actual (class object#)})) + :expected '~form, :actual (class object#)})) result#))) (defmethod assert-expr 'thrown? [msg form] @@ -492,10 +491,10 @@ body (nthnext form 2)] `(try ~@body (clojure.test/do-report {:type :fail, :message ~msg, - :expected '~form, :actual nil}) + :expected '~form, :actual nil}) (catch ~klass e# (clojure.test/do-report {:type :pass, :message ~msg, - :expected '~form, :actual e#}) + :expected '~form, :actual e#}) e#)))) (defmethod assert-expr 'thrown-with-msg? [msg form] @@ -512,7 +511,7 @@ (let [m# (.getMessage e#)] (if (re-find ~re m#) (clojure.test/do-report {:type :pass, :message ~msg, - :expected '~form, :actual e#}) + :expected '~form, :actual e#}) (clojure.test/do-report {:type :fail, :message ~msg, :expected '~form, :actual e#}))) e#)))) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 38f3622b..bff79c9c 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -10,7 +10,7 @@ [babashka.impl.clojure.java.shell :refer [shell-namespace]] [babashka.impl.clojure.main :refer [demunge]] [babashka.impl.clojure.pprint :refer [pprint-namespace]] - [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace print-stack-trace]] + [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace]] [babashka.impl.common :as common] [babashka.impl.csv :as csv] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] @@ -21,6 +21,7 @@ [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] + [clojure.stacktrace :refer [print-stack-trace]] [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] From aa4139931e8a66e3d1977339a08eff050d7e1aea Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 6 Mar 2020 10:33:22 +0100 Subject: [PATCH 054/264] [#284] Add read-string --- src/babashka/impl/clojure/core.clj | 13 +++++++++++-- src/babashka/impl/repl.clj | 8 ++++---- src/babashka/main.clj | 4 ++-- test/babashka/main_test.clj | 5 +++++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index 7374e837..aa7533a7 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -1,8 +1,10 @@ (ns babashka.impl.clojure.core {:no-doc true} - (:refer-clojure :exclude [future]) + (:refer-clojure :exclude [future read read-string]) (:require [borkdude.graal.locking :as locking] - [sci.impl.namespaces :refer [copy-core-var]])) + [clojure.tools.reader.reader-types :as r] + [sci.impl.namespaces :refer [copy-core-var]] + [sci.impl.parser :as parser])) (defn locking* [form bindings v f & args] (apply @#'locking/locking form bindings v f args)) @@ -16,6 +18,12 @@ (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs")) ret#)) +(defn read-string + ([sci-ctx s] + (let [reader (r/indexing-push-back-reader (r/push-back-reader s))] + (parser/parse-next sci-ctx reader))) + #_([opts s] (clojure.lang.RT/readString s opts))) + (def core-extras {'file-seq (copy-core-var file-seq) 'agent agent @@ -27,6 +35,7 @@ 'locking (with-meta locking* {:sci/macro true}) 'shutdown-agents shutdown-agents 'slurp (copy-core-var slurp) + 'read-string (with-meta read-string {:sci.impl/op :needs-ctx}) 'spit (copy-core-var spit) 'time (with-meta time* {:sci/macro true}) 'Throwable->map Throwable->map diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index 12fb91a6..a2c2f302 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -5,11 +5,11 @@ [clojure.java.io :as io] [clojure.string :as str] [clojure.tools.reader.reader-types :as r] - [sci.impl.interpreter :refer [eval-form]] - [sci.impl.parser :as parser] - [sci.impl.vars :as vars] [sci.core :as sci] - [sci.impl.io :as sio])) + [sci.impl.interpreter :refer [eval-form]] + [sci.impl.io :as sio] + [sci.impl.parser :as parser] + [sci.impl.vars :as vars])) (defn repl-caught "Default :caught hook for repl" diff --git a/src/babashka/main.clj b/src/babashka/main.clj index bff79c9c..c801e9e6 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -25,7 +25,7 @@ [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] - [sci.impl.interpreter :refer [eval-string*]] + [sci.impl.interpreter :refer [eval-string* eval-form]] [sci.impl.opts :as sci-opts] [sci.impl.unrestrict :refer [*unrestricted*]] [sci.impl.vars :as vars]) @@ -211,7 +211,7 @@ Everything after that is bound to *command-line-args*.")) (eval-string* sci-ctx s)))) (defn eval* [sci-ctx form] - (eval-string* sci-ctx (pr-str form))) + (eval-form sci-ctx form)) (defn start-socket-repl! [address ctx] (socket-repl/start-repl! address ctx) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 0ae37c5e..503db371 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -346,6 +346,11 @@ (testing "writer" (is (string? (bb nil "(let [sw (java.io.StringWriter.)] (clojure.pprint/pprint (range 10) sw) (str sw))"))))) +(deftest read-string-test + (testing "namespaced keyword via alias" + (is (= :clojure.string/foo + (bb nil "(ns foo (:require [clojure.string :as str])) (read-string \"::str/foo\")"))))) + ;;;; Scratch (comment From 86bc422cd68cea21673172133c1b4491966b6e0f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 6 Mar 2020 11:08:22 +0100 Subject: [PATCH 055/264] sci: eval + read-string --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index d31b0e02..d768910b 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit d31b0e02495ab052ac757e2eddb6fd581d0e47ff +Subproject commit d768910b6c4f51fc9b3331f5d8ddefc59c1f4f36 From 0b23dd0fdb4aeff687509f75c697b530b52cd0ca Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 6 Mar 2020 11:08:53 +0100 Subject: [PATCH 056/264] eval + read-string are moved to sci --- src/babashka/impl/clojure/core.clj | 11 +---------- src/babashka/main.clj | 4 ---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index aa7533a7..fe14267e 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -2,9 +2,7 @@ {:no-doc true} (:refer-clojure :exclude [future read read-string]) (:require [borkdude.graal.locking :as locking] - [clojure.tools.reader.reader-types :as r] - [sci.impl.namespaces :refer [copy-core-var]] - [sci.impl.parser :as parser])) + [sci.impl.namespaces :refer [copy-core-var]])) (defn locking* [form bindings v f & args] (apply @#'locking/locking form bindings v f args)) @@ -18,12 +16,6 @@ (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs")) ret#)) -(defn read-string - ([sci-ctx s] - (let [reader (r/indexing-push-back-reader (r/push-back-reader s))] - (parser/parse-next sci-ctx reader))) - #_([opts s] (clojure.lang.RT/readString s opts))) - (def core-extras {'file-seq (copy-core-var file-seq) 'agent agent @@ -35,7 +27,6 @@ 'locking (with-meta locking* {:sci/macro true}) 'shutdown-agents shutdown-agents 'slurp (copy-core-var slurp) - 'read-string (with-meta read-string {:sci.impl/op :needs-ctx}) 'spit (copy-core-var spit) 'time (with-meta time* {:sci/macro true}) 'Throwable->map Throwable->map diff --git a/src/babashka/main.clj b/src/babashka/main.clj index c801e9e6..04f0a844 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -210,9 +210,6 @@ Everything after that is bound to *command-line-args*.")) (sci/with-bindings {vars/current-file (.getCanonicalPath f)} (eval-string* sci-ctx s)))) -(defn eval* [sci-ctx form] - (eval-form sci-ctx form)) - (defn start-socket-repl! [address ctx] (socket-repl/start-repl! address ctx) ;; hang until SIGINT @@ -358,7 +355,6 @@ Everything after that is bound to *command-line-args*.")) _ (swap! (:env sci-ctx) (fn [env] (update-in env [:namespaces 'clojure.core] assoc - 'eval #(eval* sci-ctx %) 'load-file #(load-file* sci-ctx %)))) _ (swap! (:env sci-ctx) (fn [env] From 5723206ca2949a8e6443cdc38f8748159bcdce91 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 6 Mar 2020 16:55:52 +0100 Subject: [PATCH 057/264] Fix for slow startup time on GraalVM 20 (#288) --- resources/CutOffCoreServicesDependencies.java | 19 +++++++++++++++++++ script/compile | 3 +++ 2 files changed, 22 insertions(+) create mode 100644 resources/CutOffCoreServicesDependencies.java diff --git a/resources/CutOffCoreServicesDependencies.java b/resources/CutOffCoreServicesDependencies.java new file mode 100644 index 00000000..50f316b1 --- /dev/null +++ b/resources/CutOffCoreServicesDependencies.java @@ -0,0 +1,19 @@ +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.Delete; + +public final class CutOffCoreServicesDependencies { +} + +// @Platforms(Platform.DARWIN.class) +// @TargetClass(className = "sun.net.spi.DefaultProxySelector") +// @Delete +// final class Target_sun_net_spi_DefaultProxySelector { +// } + +@Platforms(Platform.DARWIN.class) +@TargetClass(className = "apple.security.KeychainStore") +@Delete +final class Target_apple_security_KeychainStore { +} diff --git a/script/compile b/script/compile index 97d41852..fb040df0 100755 --- a/script/compile +++ b/script/compile @@ -17,6 +17,8 @@ BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) export JAVA_HOME=$GRAALVM_HOME +$GRAALVM_HOME/bin/javac -cp $GRAALVM_HOME/jre/lib/svm/builder/svm.jar resources/CutOffCoreServicesDependencies.java + lein with-profiles +reflection do run lein do clean, uberjar @@ -37,6 +39,7 @@ args=( -jar target/babashka-$BABASHKA_VERSION-standalone.jar \ --verbose \ --no-fallback \ --no-server \ + --report-unsupported-elements-at-runtime \ "$BABASHKA_XMX" ) if [ "$BABASHKA_STATIC" = "true" ]; then From 8955431ee7888c502d63240ad0301f483716cbdd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 6 Mar 2020 22:33:58 +0100 Subject: [PATCH 058/264] Add more docstrings --- src/babashka/impl/clojure/core.clj | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index fe14267e..72db45d8 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -18,16 +18,15 @@ (def core-extras {'file-seq (copy-core-var file-seq) - 'agent agent - 'instance? instance? ;; TODO: move to sci - 'send send - 'send-off send-off - 'promise promise - 'deliver deliver + 'agent (copy-core-var agent) + 'send (copy-core-var send) + 'send-off (copy-core-var send-off) + 'promise (copy-core-var promise) + 'deliver (copy-core-var deliver) 'locking (with-meta locking* {:sci/macro true}) - 'shutdown-agents shutdown-agents + 'shutdown-agents (copy-core-var shutdown-agents) 'slurp (copy-core-var slurp) 'spit (copy-core-var spit) 'time (with-meta time* {:sci/macro true}) - 'Throwable->map Throwable->map - 'compare-and-set! compare-and-set!}) + 'Throwable->map (copy-core-var Throwable->map) + 'compare-and-set! (copy-core-var compare-and-set!)}) From 1297084d53ba2990b2cd8fd0a7f955aeb1bb342e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 7 Mar 2020 14:02:37 +0100 Subject: [PATCH 059/264] Add babashka.curl (undocumented) --- .gitmodules | 3 +++ babashka.curl | 1 + project.clj | 2 +- src/babashka/impl/curl.clj | 12 ++++++++++++ src/babashka/main.clj | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) create mode 160000 babashka.curl create mode 100644 src/babashka/impl/curl.clj diff --git a/.gitmodules b/.gitmodules index 7c3bc0cf..6bf5f5fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = sci url = https://github.com/borkdude/sci branch = master +[submodule "babashka.curl"] + path = babashka.curl + url = https://github.com/borkdude/babashka.curl diff --git a/babashka.curl b/babashka.curl new file mode 160000 index 00000000..bb6226c8 --- /dev/null +++ b/babashka.curl @@ -0,0 +1 @@ +Subproject commit bb6226c8fe11a390dd2ed771e5ca78fb87b706e3 diff --git a/project.clj b/project.clj index 528f7b9f..d28931e5 100644 --- a/project.clj +++ b/project.clj @@ -7,7 +7,7 @@ :url "https://github.com/borkdude/babashka"} :license {:name "Eclipse Public License 1.0" :url "http://opensource.org/licenses/eclipse-1.0.php"} - :source-paths ["src" "sci/src"] + :source-paths ["src" "sci/src" "babashka.curl/src"] :resource-paths ["resources" "sci/resources"] :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] diff --git a/src/babashka/impl/curl.clj b/src/babashka/impl/curl.clj new file mode 100644 index 00000000..fa036ff7 --- /dev/null +++ b/src/babashka/impl/curl.clj @@ -0,0 +1,12 @@ +(ns babashka.impl.curl + {:no-doc true} + (:require [babashka.curl :as curl])) + +(def curl-namespace + {'request curl/request + 'get curl/get + 'patch curl/patch + 'post curl/post + 'put curl/put + 'head curl/head + 'curl-command curl/curl-command}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 04f0a844..33fdbb8b 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -13,6 +13,7 @@ [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace]] [babashka.impl.common :as common] [babashka.impl.csv :as csv] + [babashka.impl.curl :refer [curl-namespace]] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] [babashka.impl.repl :as repl] [babashka.impl.socket-repl :as socket-repl] @@ -257,7 +258,8 @@ Everything after that is bound to *command-line-args*.")) 'clojure.repl {'demunge demunge} 'clojure.test t/clojure-test-namespace 'babashka.classpath {'add-classpath add-classpath*} - 'clojure.pprint pprint-namespace}) + 'clojure.pprint pprint-namespace + 'babashka.curl curl-namespace}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control From 378b592ac7f6ff195eb9be06fb10cdec0f3f87d2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 7 Mar 2020 14:10:58 +0100 Subject: [PATCH 060/264] Docs for babashka.curl --- README.md | 12 +++++++++--- babashka.curl | 2 +- src/babashka/main.clj | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a31d21bb..1bb20560 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,12 @@ $ bb '((fn [x] (println x) (when (not (signal/pipe-signal-received?)) (recur (in The namespace `babashka.signal` is aliased as `signal` in the `user` namespace. +#### babashka.curl + +The namespace `babashka.curl` is a tiny wrapper around curl. It's aliased as +`curl` in the user namespace. See +[babashka.curl](https://github.com/borkdude/babashka.curl). + ## Running a file Scripts may be executed from a file using `-f` or `--file`: @@ -647,10 +653,10 @@ mark operations (`!`, etc.) map to the double exclamation mark operations For making HTTP requests you can use: +- [babashka.curl](https://github.com/borkdude/babashka.curl). This library is + included with babashka and aliased as `curl` in the user namespace. - `slurp` for simple `GET` requests -- [clj-http-lite](https://github.com/borkdude/clj-http-lite) as a library -- `curl` via `clojure.java.shell`. Also see - [babashka.curl](https://github.com/borkdude/babashka.curl). +- [clj-http-lite](https://github.com/borkdude/clj-http-lite) as a library. ### HTTP over Unix sockets diff --git a/babashka.curl b/babashka.curl index bb6226c8..90387425 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit bb6226c8fe11a390dd2ed771e5ca78fb87b706e3 +Subproject commit 90387425f425cfd3dc955ca2a4d63325bc4b8c2d diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 33fdbb8b..342d6ffe 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -228,7 +228,8 @@ Everything after that is bound to *command-line-args*.")) io clojure.java.io async clojure.core.async csv clojure.data.csv - json cheshire.core}) + json cheshire.core + curl babashka.curl}) (def cp-state (atom nil)) From 5660b76ab75949fcfcfc03a0b80462b827e2a579 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 7 Mar 2020 14:13:30 +0100 Subject: [PATCH 061/264] v0.0.75 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 5a4e5b73..335f30ac 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.75-SNAPSHOT \ No newline at end of file +0.0.75 \ No newline at end of file From 4287ebd9393c4fa3f8e14c71fae040cacb081bb3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 7 Mar 2020 14:28:52 +0100 Subject: [PATCH 062/264] Version bump --- babashka.curl | 2 +- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/babashka.curl b/babashka.curl index 90387425..d04b1c1a 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 90387425f425cfd3dc955ca2a4d63325bc4b8c2d +Subproject commit d04b1c1a8ab47ecbcd572e833514bbdfc5430061 diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 05389a0e..335f30ac 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.74 \ No newline at end of file +0.0.75 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 335f30ac..7a34330c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.75 \ No newline at end of file +0.0.76-SNAPSHOT \ No newline at end of file From 4812f755fb06690b94e399d3aa22239d1bb08faa Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 7 Mar 2020 15:19:36 +0100 Subject: [PATCH 063/264] babashka.curl --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index d04b1c1a..e281fc02 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit d04b1c1a8ab47ecbcd572e833514bbdfc5430061 +Subproject commit e281fc02a055f0d45735e7dfc088bfd54257b893 From 07d71d0869af248aa54a1c289f46b6353bf2b243 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 8 Mar 2020 12:05:34 +0100 Subject: [PATCH 064/264] README: add 4bb --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1bb20560..94429114 100644 --- a/README.md +++ b/README.md @@ -657,6 +657,8 @@ For making HTTP requests you can use: included with babashka and aliased as `curl` in the user namespace. - `slurp` for simple `GET` requests - [clj-http-lite](https://github.com/borkdude/clj-http-lite) as a library. +- `clojure.java.shell` or `java.lang.ProcessBuilder` for shelling out to your + favorite command line http client ### HTTP over Unix sockets @@ -813,11 +815,9 @@ $ bb -e "(require '[lambdaisland.regal :as regal]) (regal/regex [:* \"ab\"])" #"(?:\Qab\E)*" ``` -#### [spartan.test](https://github.com/borkdude/spartan.test/) - -A minimal test framework compatible with babashka. This library is deprecated -since babashka v0.0.68 which has `clojure.test` built-in. +#### [4bb](https://github.com/porkostomus/4bb) +4clojure as a babashka script! ### Blogs From 34be5b61f43f8c250a8df64fe7de90337366f2f4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 8 Mar 2020 17:38:08 +0100 Subject: [PATCH 065/264] Include curl in Docker image --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8de22c80..b07edc43 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,9 @@ COPY . . RUN ./script/compile -FROM busybox:musl +FROM alpine:latest +RUN apk add —no-cache curl RUN mkdir -p /usr/local/bin COPY --from=BASE /opt/bb /usr/local/bin/bb CMD ["bb"] From 3b42b9032c7b4202ea274e263478a8bd8f33fd2b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 8 Mar 2020 17:50:51 +0100 Subject: [PATCH 066/264] Fix Docker --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b07edc43..00857401 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN ./script/compile FROM alpine:latest -RUN apk add —no-cache curl +RUN apk add -U curl RUN mkdir -p /usr/local/bin COPY --from=BASE /opt/bb /usr/local/bin/bb CMD ["bb"] From e3b075e3ab0218f75b22f7f430ac9fe6199fccb3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 8 Mar 2020 17:53:24 +0100 Subject: [PATCH 067/264] Docker: --no-cache --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 00857401..5b1d5687 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN ./script/compile FROM alpine:latest -RUN apk add -U curl +RUN apk add --no-cache curl RUN mkdir -p /usr/local/bin COPY --from=BASE /opt/bb /usr/local/bin/bb CMD ["bb"] From e7328173242f53c383485527c11e1295095d7926 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 9 Mar 2020 09:43:10 +0100 Subject: [PATCH 068/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index d768910b..44b1d050 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit d768910b6c4f51fc9b3331f5d8ddefc59c1f4f36 +Subproject commit 44b1d0509511d63fcf3c28f379b2a0ad6c70d9be From 26a799f54e3404d6c9ad6cc7bba1e0874aed0628 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 9 Mar 2020 10:58:43 +0100 Subject: [PATCH 069/264] babashka.curl --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index e281fc02..3104d234 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit e281fc02a055f0d45735e7dfc088bfd54257b893 +Subproject commit 3104d234a63fca71f0d3557c5d3dc23f4fbc294f From bf8030f1f81b12e30f92d46f1c2435298374dec3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 12 Mar 2020 11:01:45 +0100 Subject: [PATCH 070/264] README --- README.md | 5 +++++ sci | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94429114..3ad136d1 100644 --- a/README.md +++ b/README.md @@ -610,6 +610,11 @@ $ A socket REPL client for Emacs is [inf-clojure](https://github.com/clojure-emacs/inf-clojure). +Editor plugins offering auto-completion support when connected to a babashka socket REPL: + +- Atom: [chlorine](https://github.com/mauricioszabo/atom-chlorine) +- Vim: [vim-iced](https://github.com/liquidz/vim-iced) + ## Spawning and killing a process Use the `java.lang.ProcessBuilder` class. diff --git a/sci b/sci index 44b1d050..9dde0e3e 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 44b1d0509511d63fcf3c28f379b2a0ad6c70d9be +Subproject commit 9dde0e3e80efa4ecb6e320dcbb0bf3da2d4eb22b From 7dc1fab97698ab80d53351a8b4d7f3149790feee Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 13 Mar 2020 12:03:57 +0100 Subject: [PATCH 071/264] sci: add ns-unmap --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 9dde0e3e..4fd68d04 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 9dde0e3e80efa4ecb6e320dcbb0bf3da2d4eb22b +Subproject commit 4fd68d044a1008bc11412b19f2259b5649efe554 From a6681ef38a6b957955fd02385028917818c50139 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Mar 2020 20:25:37 +0100 Subject: [PATCH 072/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 4fd68d04..aa73bdef 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 4fd68d044a1008bc11412b19f2259b5649efe554 +Subproject commit aa73bdef358a089733f9e20b1673c551f3ccdd6b From 645cea071eb03dbfc8d31ddf24927a69951fc6dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Mar 2020 20:30:30 +0100 Subject: [PATCH 073/264] README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3ad136d1..245a74b5 100644 --- a/README.md +++ b/README.md @@ -466,6 +466,10 @@ $ bb "(my-gist-script/-main)" Hello from gist script! ``` +Also see the +[babashka.classpath](https://github.com/borkdude/babashka/#babashkaclasspath) +namespace which allows dynamically adding to the classpath. + ### Deps.clj The [`deps.clj`](https://github.com/borkdude/deps.clj/) script can be used to work with `deps.edn`-based projects: From 5b50ba760e0b956d43d9a1927d3f8ac265fe21ad Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 14:28:19 +0100 Subject: [PATCH 074/264] [#296] add support for cprops lib (#297) --- doc/dev.md | 9 +++++---- script/lib_tests/cprop_test | 18 ++++++++++++++++++ script/run_lib_tests | 1 + src/babashka/impl/classes.clj | 4 ++++ src/babashka/impl/clojure/core.clj | 4 +++- src/babashka/main.clj | 2 ++ 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100755 script/lib_tests/cprop_test diff --git a/doc/dev.md b/doc/dev.md index 19f5151e..c97f7f8f 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -53,11 +53,12 @@ Then run: Keep notes here about how adding libraries and classes to Babashka affects the binary size. - +2020/03/19 Added java.lang.NumberFormatException, java.lang.RuntimeException, +java.util.MissingResourceException and java.util.Properties to support +[cprop](https://github.com/tolitius/cprop/). +41025180 - 40729908 = 295kb added. - - -2020/02/21, +2020/02/21 Added java.time.temporal.ChronoUnit 40651596 - 40598260 = 53kb added. diff --git a/script/lib_tests/cprop_test b/script/lib_tests/cprop_test new file mode 100755 index 00000000..71ef87bd --- /dev/null +++ b/script/lib_tests/cprop_test @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -eo pipefail + +export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {cprop {:mvn/version "0.1.16"}}}') + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + + +CPROP_ENV="hello" $BB_CMD " +(require '[cprop.core :refer [load-config]]) +(require '[cprop.source :refer [from-system-props from-env]]) +(println (:cprop-env (from-env))) +" diff --git a/script/run_lib_tests b/script/run_lib_tests index 87e152be..10c7f271 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -9,3 +9,4 @@ script/lib_tests/clojure_csv_test script/lib_tests/regal_test script/lib_tests/medley_test script/lib_tests/babashka_curl_test +script/lib_tests/cprop_test diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index d69a0d9a..25a057e4 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -33,7 +33,9 @@ java.lang.Exception java.lang.Integer java.lang.Long + java.lang.NumberFormatException java.lang.Math + java.lang.RuntimeException java.util.concurrent.LinkedBlockingQueue java.lang.Object java.lang.String @@ -90,6 +92,8 @@ java.util.Base64$Decoder java.util.Base64$Encoder java.util.Date + java.util.MissingResourceException + java.util.Properties java.util.UUID java.util.concurrent.TimeUnit java.util.zip.InflaterInputStream diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index 72db45d8..c7e9452a 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -2,6 +2,7 @@ {:no-doc true} (:refer-clojure :exclude [future read read-string]) (:require [borkdude.graal.locking :as locking] + [sci.core :as sci] [sci.impl.namespaces :refer [copy-core-var]])) (defn locking* [form bindings v f & args] @@ -29,4 +30,5 @@ 'spit (copy-core-var spit) 'time (with-meta time* {:sci/macro true}) 'Throwable->map (copy-core-var Throwable->map) - 'compare-and-set! (copy-core-var compare-and-set!)}) + 'compare-and-set! (copy-core-var compare-and-set!) + '*data-readers* (sci/new-dynamic-var '*data-readers* nil)}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 342d6ffe..3199d587 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -343,7 +343,9 @@ Everything after that is bound to *command-line-args*.")) File java.io.File Long java.lang.Long Math java.lang.Math + NumberFormatException java.lang.NumberFormatException Object java.lang.Object + RuntimeException java.lang.RuntimeException ProcessBuilder java.lang.ProcessBuilder String java.lang.String StringBuilder java.lang.StringBuilder From 4a3df13381b402704a63d1acba6404850dcb9e65 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 14:37:42 +0100 Subject: [PATCH 075/264] Add cprop to libs --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 245a74b5..1c3699dd 100644 --- a/README.md +++ b/README.md @@ -828,6 +828,10 @@ $ bb -e "(require '[lambdaisland.regal :as regal]) (regal/regex [:* \"ab\"])" 4clojure as a babashka script! +#### [cprop](https://github.com/tolitius/cprop/) + +A clojure configuration libary. Latest test version: `"0.1.16"`. + ### Blogs - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks From 4db28b45e809bd40e68835ff2564bd326831e0cb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 15:12:15 +0100 Subject: [PATCH 076/264] [#293] reset ns after load-file --- src/babashka/main.clj | 10 +++++++--- test/babashka/main_test.clj | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 3199d587..f7f5371e 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -29,7 +29,8 @@ [sci.impl.interpreter :refer [eval-string* eval-form]] [sci.impl.opts :as sci-opts] [sci.impl.unrestrict :refer [*unrestricted*]] - [sci.impl.vars :as vars]) + [sci.impl.vars :as vars] + [sci.impl.types :as sci-types]) (:gen-class)) (binding [*unrestricted* true] @@ -207,9 +208,12 @@ Everything after that is bound to *command-line-args*.")) (defn load-file* [sci-ctx f] (let [f (io/file f) - s (slurp f)] + s (slurp f) + prev-ns @vars/current-ns] (sci/with-bindings {vars/current-file (.getCanonicalPath f)} - (eval-string* sci-ctx s)))) + (try + (eval-string* sci-ctx s) + (finally (sci-types/setVal vars/current-ns prev-ns)))))) (defn start-socket-repl! [address ctx] (socket-repl/start-repl! address ctx) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 503db371..c4a90a47 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -118,9 +118,13 @@ (deftest load-file-test (let [tmp (java.io.File/createTempFile "script" ".clj")] - (spit tmp "(defn foo [x y] (+ x y)) (defn bar [x y] (* x y))") - (is (= "120\n" (test-utils/bb nil (format "(load-file \"%s\") (bar (foo 10 30) 3)" - (.getPath tmp))))))) + (spit tmp "(ns foo) (defn foo [x y] (+ x y)) (defn bar [x y] (* x y))") + (is (= "120\n" (test-utils/bb nil (format "(load-file \"%s\") (foo/bar (foo/foo 10 30) 3)" + (.getPath tmp))))) + (testing "namespace is restored after load file" + (is (= 'start-ns + (bb nil (format "(ns start-ns) (load-file \"%s\") (ns-name *ns*)" + (.getPath tmp)))))))) (deftest eval-test (is (= "120\n" (test-utils/bb nil "(eval '(do (defn foo [x y] (+ x y)) From a18a5c345c3b7abdfb53f9d0b5a76229042aafd1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 15:37:02 +0100 Subject: [PATCH 077/264] Socket-REPL: default to port 1666 --- src/babashka/main.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index f7f5371e..a224eed3 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -112,7 +112,8 @@ (let [options (next options)] (recur (next options) (assoc opts-map - :socket-repl (first options)))) + :socket-repl (or (first options) + "1666")))) ("--eval", "-e") (let [options (next options)] (recur (next options) From 64df0fd0158b2f380be5e0e2fb5fbee6d82e9bb6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 15:47:54 +0100 Subject: [PATCH 078/264] docs --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1c3699dd..4b74b060 100644 --- a/README.md +++ b/README.md @@ -611,11 +611,14 @@ bb=> :repl/quit $ ``` -A socket REPL client for Emacs is -[inf-clojure](https://github.com/clojure-emacs/inf-clojure). - Editor plugins offering auto-completion support when connected to a babashka socket REPL: +- Emacs: [inf-clojure](https://github.com/clojure-emacs/inf-clojure): + To connect: + `M-x inf-clojure-connect localhost 1666` + Before evaluating from a Clojure buffer: + `M-x inf-clojure-minor-mode` + - Atom: [chlorine](https://github.com/mauricioszabo/atom-chlorine) - Vim: [vim-iced](https://github.com/liquidz/vim-iced) From d2ea4ee1bb0ed5573d1d8c7be97b611355fc85c6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 15:52:30 +0100 Subject: [PATCH 079/264] Socket REPL docs --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4b74b060..5ac8d5c7 100644 --- a/README.md +++ b/README.md @@ -614,9 +614,13 @@ $ Editor plugins offering auto-completion support when connected to a babashka socket REPL: - Emacs: [inf-clojure](https://github.com/clojure-emacs/inf-clojure): + To connect: + `M-x inf-clojure-connect localhost 1666` + Before evaluating from a Clojure buffer: + `M-x inf-clojure-minor-mode` - Atom: [chlorine](https://github.com/mauricioszabo/atom-chlorine) From ef06175678e421c99e870de9cb3b39a927ba7c9f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 17:16:42 +0100 Subject: [PATCH 080/264] [#264] Add transit-clj (#298) --- .gitignore | 2 +- README.md | 1 + doc/dev.md | 3 +++ project.clj | 3 ++- src/babashka/impl/classes.clj | 4 +++- src/babashka/impl/transit.clj | 12 ++++++++++++ src/babashka/main.clj | 13 ++++++++----- test-resources/babashka/transit.clj | 18 ++++++++++++++++++ test/babashka/main_test.clj | 5 ++++- test/babashka/transit_test.clj | 13 +++++++++++++ 10 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/babashka/impl/transit.clj create mode 100644 test-resources/babashka/transit.clj create mode 100644 test/babashka/transit_test.clj diff --git a/.gitignore b/.gitignore index 4d308908..1b98c17b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,6 @@ pom.xml.asc !java/src/babashka/impl/LockFix.class !test-resources/babashka/src_for_classpath_test/foo.jar .cpcache -reflection.json +*reflection.json /tmp /reports diff --git a/README.md b/README.md index 5ac8d5c7..63ba3c0c 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,7 @@ enumerated explicitly. - [`clojure.tools.cli`](https://github.com/clojure/tools.cli) aliased as `tools.cli` - [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv` - [`cheshire.core`](https://github.com/dakrone/cheshire) aliased as `json` +- [`cognitect.transit`](https://github.com/cognitect/transit-clj) aliased as `transit` A selection of java classes are available, see `babashka/impl/classes.clj`. diff --git a/doc/dev.md b/doc/dev.md index c97f7f8f..4fefb30b 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -53,6 +53,9 @@ Then run: Keep notes here about how adding libraries and classes to Babashka affects the binary size. +2020/03/20 Added transit write, writer, read, reader +42004796 - 41025212 = 980kb added (305kb zipped). + 2020/03/19 Added java.lang.NumberFormatException, java.lang.RuntimeException, java.util.MissingResourceException and java.util.Properties to support [cprop](https://github.com/tolitius/cprop/). diff --git a/project.clj b/project.clj index d28931e5..becb1397 100644 --- a/project.clj +++ b/project.clj @@ -18,7 +18,8 @@ [org.clojure/tools.cli "0.4.2"] [org.clojure/data.csv "1.0.0"] [cheshire "5.10.0"] - [fipp "0.6.22"]] + [fipp "0.6.22"] + [com.cognitect/transit-clj "1.0.324"]] :profiles {:test {:dependencies [[clj-commons/conch "0.9.2"] [com.clojure-goes-fast/clj-async-profiler "0.4.0"]]} :uberjar {:global-vars {*assert* false} diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 25a057e4..4a4e404a 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -198,7 +198,9 @@ (instance? java.io.ByteArrayOutputStream v) java.io.ByteArrayOutputStream (instance? java.security.MessageDigest v) - java.security.MessageDigest))))) + java.security.MessageDigest + (instance? java.io.InputStream v) + java.io.InputStream))))) (def class-map (gen-class-map)) diff --git a/src/babashka/impl/transit.clj b/src/babashka/impl/transit.clj new file mode 100644 index 00000000..e7c84311 --- /dev/null +++ b/src/babashka/impl/transit.clj @@ -0,0 +1,12 @@ +(ns babashka.impl.transit + (:require [cognitect.transit :as transit] + [sci.impl.namespaces :refer [copy-var]] + [sci.impl.vars :as vars])) + +(def tns (vars/->SciNamespace 'cognitect.transit nil)) + +(def transit-namespace + {'write (copy-var transit/write tns) + 'writer (copy-var transit/writer tns) + 'read (copy-var transit/read tns) + 'reader (copy-var transit/reader tns)}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index a224eed3..3f9d1d37 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -19,6 +19,7 @@ [babashka.impl.socket-repl :as socket-repl] [babashka.impl.test :as t] [babashka.impl.tools.cli :refer [tools-cli-namespace]] + [babashka.impl.transit :refer [transit-namespace]] [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] @@ -26,11 +27,11 @@ [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] - [sci.impl.interpreter :refer [eval-string* eval-form]] + [sci.impl.interpreter :refer [eval-string*]] [sci.impl.opts :as sci-opts] + [sci.impl.types :as sci-types] [sci.impl.unrestrict :refer [*unrestricted*]] - [sci.impl.vars :as vars] - [sci.impl.types :as sci-types]) + [sci.impl.vars :as vars]) (:gen-class)) (binding [*unrestricted* true] @@ -234,7 +235,8 @@ Everything after that is bound to *command-line-args*.")) async clojure.core.async csv clojure.data.csv json cheshire.core - curl babashka.curl}) + curl babashka.curl + transit cognitect.transit}) (def cp-state (atom nil)) @@ -265,7 +267,8 @@ Everything after that is bound to *command-line-args*.")) 'clojure.test t/clojure-test-namespace 'babashka.classpath {'add-classpath add-classpath*} 'clojure.pprint pprint-namespace - 'babashka.curl curl-namespace}) + 'babashka.curl curl-namespace + 'cognitect.transit transit-namespace}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control diff --git a/test-resources/babashka/transit.clj b/test-resources/babashka/transit.clj new file mode 100644 index 00000000..3d3bda6a --- /dev/null +++ b/test-resources/babashka/transit.clj @@ -0,0 +1,18 @@ +(require '[cognitect.transit :as transit]) +(import [java.io ByteArrayInputStream ByteArrayOutputStream]) + +;; Write data to a stream +(def out (ByteArrayOutputStream. 4096)) +(def writer (transit/writer out :json)) +(transit/write writer "foo") +(transit/write writer {:a [1 2]}) + +;; Take a peek at the JSON +(.toString out) +;; => "{\"~#'\":\"foo\"} [\"^ \",\"~:a\",[1,2]]" + +;; Read data from a stream +(def in (ByteArrayInputStream. (.toByteArray out))) +(def reader (transit/reader in :json)) +(prn (transit/read reader)) ;; => "foo" +(prn (transit/read reader)) ;; => {:a [1 2]} diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index c4a90a47..ac98ab9a 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -29,7 +29,7 @@ (deftest main-test (testing "-io behaves as identity" - (= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" "*input*"))) + (is (= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" "*input*")))) (testing "if and when" (is (= 1 (bb 0 '(if (zero? *input*) 1 2)))) (is (= 2 (bb 1 '(if (zero? *input*) 1 2)))) @@ -355,6 +355,9 @@ (is (= :clojure.string/foo (bb nil "(ns foo (:require [clojure.string :as str])) (read-string \"::str/foo\")"))))) +(deftest available-stream-test + (is (= 0 (bb nil "(.available System/in)")))) + ;;;; Scratch (comment diff --git a/test/babashka/transit_test.clj b/test/babashka/transit_test.clj new file mode 100644 index 00000000..86523771 --- /dev/null +++ b/test/babashka/transit_test.clj @@ -0,0 +1,13 @@ +(ns babashka.transit-test + (:require + [babashka.test-utils :as test-utils] + [clojure.java.io :as io] + [clojure.test :as t :refer [deftest is]])) + +(defn bb [& args] + (apply test-utils/bb nil (map str args))) + +(deftest transit-test + (is (= "\"foo\"\n{:a [1 2]}\n" + (bb (format "(load-file \"%s\")" + (.getPath (io/file "test-resources" "babashka" "transit.clj"))))))) From 44471c97ec8b3d1b9673662411468f260e5b4329 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 22:27:18 +0100 Subject: [PATCH 081/264] v0.0.76 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 7a34330c..d9bac80e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.76-SNAPSHOT \ No newline at end of file +0.0.76 \ No newline at end of file From adaef58f5e982560c93a48702ae112b29bc37093 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 23:39:28 +0100 Subject: [PATCH 082/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- sci | 2 +- test/babashka/main_test.clj | 13 ++++++++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 335f30ac..d9bac80e 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.75 \ No newline at end of file +0.0.76 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d9bac80e..05423a18 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.76 \ No newline at end of file +0.0.77-SNAPSHOT \ No newline at end of file diff --git a/sci b/sci index aa73bdef..17b14cae 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit aa73bdef358a089733f9e20b1673c551f3ccdd6b +Subproject commit 17b14cae6260ad56a37fb3f46de16255ae90f9b8 diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index ac98ab9a..eb52dcf0 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -228,7 +228,18 @@ (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb")))) (deftest try-catch-test - (is (zero? (bb nil "(try (/ 1 0) (catch ArithmeticException _ 0))")))) + (is (zero? (bb nil "(try (/ 1 0) (catch ArithmeticException _ 0))"))) + (is (= :got-it (bb nil " +(defn foo [] + (throw (java.util.MissingResourceException. \"o noe!\" \"\" \"\"))) + +(defn bar + [] + (try (foo) + (catch java.util.MissingResourceException _ + :got-it))) +(bar) +")))) (deftest reader-conditionals-test (is (= :hello (bb nil "#?(:bb :hello :default :bye)"))) From 9835b0278587a4e97457600cbfa1da7780f10b2b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 23:44:21 +0100 Subject: [PATCH 083/264] Fix exception handling --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- sci | 2 +- test/babashka/main_test.clj | 13 ++++++++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 335f30ac..d9bac80e 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.75 \ No newline at end of file +0.0.76 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d9bac80e..05423a18 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.76 \ No newline at end of file +0.0.77-SNAPSHOT \ No newline at end of file diff --git a/sci b/sci index aa73bdef..17b14cae 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit aa73bdef358a089733f9e20b1673c551f3ccdd6b +Subproject commit 17b14cae6260ad56a37fb3f46de16255ae90f9b8 diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index ac98ab9a..eb52dcf0 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -228,7 +228,18 @@ (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb")))) (deftest try-catch-test - (is (zero? (bb nil "(try (/ 1 0) (catch ArithmeticException _ 0))")))) + (is (zero? (bb nil "(try (/ 1 0) (catch ArithmeticException _ 0))"))) + (is (= :got-it (bb nil " +(defn foo [] + (throw (java.util.MissingResourceException. \"o noe!\" \"\" \"\"))) + +(defn bar + [] + (try (foo) + (catch java.util.MissingResourceException _ + :got-it))) +(bar) +")))) (deftest reader-conditionals-test (is (= :hello (bb nil "#?(:bb :hello :default :bye)"))) From 5f0c0ebd7fcea6051c5d135645b16017d4245fd5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 23:51:16 +0100 Subject: [PATCH 084/264] Bring deps.edn up to date --- deps.edn | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deps.edn b/deps.edn index 7d1fd250..644d698e 100644 --- a/deps.edn +++ b/deps.edn @@ -1,4 +1,4 @@ -{:paths ["src" "sci/src" "resources" "sci/resources"], +{:paths ["src" "sci/src" "babashka.curl/src" "resources" "sci/resources"], :deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}, org.clojure/tools.reader {:mvn/version "1.3.2"}, borkdude/edamame {:mvn/version "0.0.10"}, @@ -8,7 +8,8 @@ org.clojure/tools.cli {:mvn/version "0.4.2"}, org.clojure/data.csv {:mvn/version "1.0.0"}, cheshire {:mvn/version "5.10.0"} - fipp {:mvn/version "0.6.22"}} + fipp {:mvn/version "0.6.22"} + com.cognitect/transit-clj {:mvn/version "1.0.324"}} :aliases {:main {:main-opts ["-m" "babashka.main"]} :profile From 3122d8ebe74dddf0f20f2251494f3970bab81a1d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Mar 2020 23:53:17 +0100 Subject: [PATCH 085/264] v0.0.77 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 05423a18..045bf4f1 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.77-SNAPSHOT \ No newline at end of file +0.0.77 \ No newline at end of file From d70d902901eb90363846ba3f4cc247159498290c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 00:11:30 +0100 Subject: [PATCH 086/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index d9bac80e..b76f49a4 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.76 \ No newline at end of file +0.0.77 diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index b76f49a4..d04aca5c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.77 +0.0.78-SNAPSHOT \ No newline at end of file From 4a0b3b9c658f483199f70cd6d95da5c4fc576804 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 11:41:26 +0100 Subject: [PATCH 087/264] README: add sha example --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 63ba3c0c..8c726099 100644 --- a/README.md +++ b/README.md @@ -1038,6 +1038,21 @@ clojure.core/ffirst Same as (first (first x)) ``` +### SHA hash string and print in hex + +`sha.clj`: +``` +(def hashed (.digest (.getInstance java.security.MessageDigest "SHA-1") + (.getBytes "babashka"))) +(doseq [b hashed] + (print (format "%02X" b))) +``` + +``` shell +bb sha.clj +0AB318BE3A646EEB1E592781CBFE4AE59701EDDF +``` + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support From 5b88953d0552136e66a5377b3fc6590a92ab6477 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 11:43:14 +0100 Subject: [PATCH 088/264] README: highlighting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c726099..296d5b24 100644 --- a/README.md +++ b/README.md @@ -1041,7 +1041,7 @@ clojure.core/ffirst ### SHA hash string and print in hex `sha.clj`: -``` +``` clojure (def hashed (.digest (.getInstance java.security.MessageDigest "SHA-1") (.getBytes "babashka"))) (doseq [b hashed] From fd61bb1a1cda1d811ceb6a09556e92ad417d9fb4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 11:48:06 +0100 Subject: [PATCH 089/264] README: enhance sha1 example --- README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 296d5b24..a068baeb 100644 --- a/README.md +++ b/README.md @@ -1040,17 +1040,26 @@ clojure.core/ffirst ### SHA hash string and print in hex -`sha.clj`: +`sha1.clj`: ``` clojure -(def hashed (.digest (.getInstance java.security.MessageDigest "SHA-1") - (.getBytes "babashka"))) -(doseq [b hashed] - (print (format "%02X" b))) +#!/usr/bin/env bb + +(defn sha1 + [s] + (let [hashed (.digest (.getInstance java.security.MessageDigest "SHA-1") + (.getBytes s)) + sw (java.io.StringWriter.)] + (binding [*out* sw] + (doseq [byte hashed] + (print (format "%02X" byte)))) + (str sw))) + +(sha1 (first *command-line-args*)) ``` ``` shell -bb sha.clj -0AB318BE3A646EEB1E592781CBFE4AE59701EDDF +sha1.clj +"0AB318BE3A646EEB1E592781CBFE4AE59701EDDF" ``` ## Thanks From 41fe2b994f8279c685870afe48f725f904e531b4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 11:49:45 +0100 Subject: [PATCH 090/264] README: title --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a068baeb..00f04adc 100644 --- a/README.md +++ b/README.md @@ -1038,7 +1038,7 @@ clojure.core/ffirst Same as (first (first x)) ``` -### SHA hash string and print in hex +### Cryptographic hash `sha1.clj`: ``` clojure From 125340ba3df78d618cb282b2264a1d4af68f61e4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 11:50:40 +0100 Subject: [PATCH 091/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00f04adc..63499211 100644 --- a/README.md +++ b/README.md @@ -1058,7 +1058,7 @@ clojure.core/ffirst ``` ``` shell -sha1.clj +$ sha1.clj babashka "0AB318BE3A646EEB1E592781CBFE4AE59701EDDF" ``` From 6aa2389e6fe4623b1b3ce3820c99b9fdb1f3950a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 14:37:29 +0100 Subject: [PATCH 092/264] README --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 63499211..77da1088 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,10 @@ You may also download a binary from [Github](https://github.com/borkdude/babashka/releases). For linux there is a static binary available which can be used on Alpine. +## Docker + +Check out the image on [Docker hub](https://hub.docker.com/r/borkdude/babashka/). + ## Usage ``` shellsession @@ -1062,6 +1066,26 @@ $ sha1.clj babashka "0AB318BE3A646EEB1E592781CBFE4AE59701EDDF" ``` +### Package script as Docker image + +`Dockerfile`: +``` dockerfile +FROM borkdude/babashka +RUN echo $'\ +(println "Your command line args:" *command-line-args*)\ +'\ +>> script.clj + +ENTRYPOINT ["bb", "script.clj"] +``` + +``` shell +$ docker build . -t script +... +$ docker run --rm script 1 2 3 +Your command line args: (1 2 3) +``` + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support From ce028644fc3835a4287be10142aeb64b72d46eee Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 17:27:41 +0100 Subject: [PATCH 093/264] comb --- README.md | 18 ++++++++++++++++++ script/lib_tests/comb_test | 21 +++++++++++++++++++++ script/run_lib_tests | 1 + 3 files changed, 40 insertions(+) create mode 100755 script/lib_tests/comb_test diff --git a/README.md b/README.md index 77da1088..4fc024b1 100644 --- a/README.md +++ b/README.md @@ -844,6 +844,24 @@ $ bb -e "(require '[lambdaisland.regal :as regal]) (regal/regex [:* \"ab\"])" A clojure configuration libary. Latest test version: `"0.1.16"`. +#### [comb](https://github.com/weavejester/comb) + +Simple templating system for Clojure. Latest tested version: `"0.1.1"`. + +``` clojure +$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {comb {:mvn/version "0.1.1"}}}') +$ rlwrap bb +... +user=> (require '[comb.template :as template]) +user=> (template/eval "<% (dotimes [x 3] %>foo<% ) %>") +"foofoofoo" +user=> (template/eval "Hello <%= name %>" {:name "Alice"}) +"Hello Alice" +user=> (def hello (template/fn [name] "Hello <%= name %>")) +user=> (hello "Alice") +"Hello Alice" +``` + ### Blogs - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks diff --git a/script/lib_tests/comb_test b/script/lib_tests/comb_test new file mode 100755 index 00000000..3e6e88df --- /dev/null +++ b/script/lib_tests/comb_test @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -eo pipefail + +export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {comb {:mvn/version "0.1.1"}}}') + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + + +$BB_CMD ' +(ns foo (:require [comb.template :as template])) +(prn (template/eval "<% (dotimes [x 3] %>foo<% ) %>")) +(prn (template/eval "Hello <%= name %>" {:name "Alice"})) +(def hello + (template/fn [name] "Hello <%= name %>")) +(prn (hello "Alice")) +' diff --git a/script/run_lib_tests b/script/run_lib_tests index 10c7f271..aaa56bf3 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -10,3 +10,4 @@ script/lib_tests/regal_test script/lib_tests/medley_test script/lib_tests/babashka_curl_test script/lib_tests/cprop_test +script/lib_tests/comb_test From b14d239ebb72768e72a1c2abeda903b839aeb7df Mon Sep 17 00:00:00 2001 From: Dainius Jocas Date: Sat, 21 Mar 2020 21:17:57 +0200 Subject: [PATCH 094/264] Support AWS Lambda custom runtime (#305) * environment variable to disable handling of SIGPIPE * rename env variable to BABASHKA_DISABLE_PIPE_HANDLER --- README.md | 4 ++++ src/babashka/main.clj | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fc024b1..14968b21 100644 --- a/README.md +++ b/README.md @@ -1104,6 +1104,10 @@ $ docker run --rm script 1 2 3 Your command line args: (1 2 3) ``` +## Package babashka script as a AWS Lambda + +AWS Lambda runtime doesn't support signals, therefore babashka has to disable handling of the SIGPIPE. This can be done by setting `BABASHKA_DISABLE_PIPE_HANDLER` to `true`. + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 3f9d1d37..2e6ec6b6 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -289,7 +289,8 @@ Everything after that is bound to *command-line-args*.")) (defn main [& args] - (handle-pipe!) + (when-not (Boolean/valueOf ^String (System/getenv "BABASHKA_DISABLE_PIPE_HANDLER")) + (handle-pipe!)) #_(binding [*out* *err*] (prn "M" (meta (get bindings 'future)))) (binding [*unrestricted* true] From 02f5a85db3295ed9b78b9729802999a3c7c9df86 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 22:48:04 +0100 Subject: [PATCH 095/264] Fix bug with *input* when used in code from classpath --- sci | 2 +- src/babashka/main.clj | 41 ++++++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/sci b/sci index 17b14cae..e0d5313c 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 17b14cae6260ad56a37fb3f46de16255ae90f9b8 +Subproject commit e0d5313c02d5ac62bdb4311cf41b0d565b7b6d22 diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 2e6ec6b6..38a630aa 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -202,10 +202,6 @@ Everything after that is bound to *command-line-args*.")) (str/replace x #"^#!.*" "")) (throw (Exception. (str "File does not exist: " file)))))) -(defn read-edn [] - (edn/read {;;:readers *data-readers* - :eof ::EOF} *in*)) - (def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false)) (defn load-file* [sci-ctx f] @@ -309,7 +305,8 @@ Everything after that is bound to *command-line-args*.")) ::EOF (if stream? (if shell-in (or (read-line) ::EOF) - (read-edn)) + (edn/read {;;:readers *data-readers* + :eof ::EOF} *in*)) (delay (cond shell-in (shell-seq *in*) edn-in @@ -366,16 +363,20 @@ Everything after that is bound to *command-line-args*.")) ctx (addons/future ctx) sci-ctx (sci-opts/init ctx) _ (vreset! common/ctx sci-ctx) + input-var (sci/new-dynamic-var '*input* nil) _ (swap! (:env sci-ctx) (fn [env] - (update-in env [:namespaces 'clojure.core] assoc - 'load-file #(load-file* sci-ctx %)))) - _ (swap! (:env sci-ctx) - (fn [env] - (assoc-in env [:namespaces 'clojure.main 'repl] - (fn [& opts] - (let [opts (apply hash-map opts)] - (repl/start-repl! sci-ctx opts)))))) + (update env :namespaces + (fn [namespaces] [:namespaces 'clojure.main 'repl] + (-> namespaces + (assoc-in ['clojure.core 'load-file] #(load-file* sci-ctx %)) + (assoc-in ['clojure.main 'repl] + (fn [& opts] + (let [opts (apply hash-map opts)] + (repl/start-repl! sci-ctx opts)))) + (assoc-in ['user (with-meta '*input* + (when-not stream? + {:sci.impl/deref! true}))] input-var)))))) preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim)) [expressions exit-code] (cond expressions [expressions nil] @@ -405,15 +406,13 @@ Everything after that is bound to *command-line-args*.")) socket-repl [(start-socket-repl! socket-repl sci-ctx) 0] (not (str/blank? expression)) (try - (loop [in (read-next *in*)] - (let [_ (swap! env update-in [:namespaces 'user] - assoc (with-meta '*input* - (when-not stream? - {:sci.impl/deref! true})) - (sci/new-dynamic-var '*input* in))] + (loop [] + (let [in (read-next *in*)] (if (identical? ::EOF in) [nil 0] ;; done streaming - (let [res [(let [res (eval-string* sci-ctx expression)] + (let [res [(let [res + (sci/binding [input-var in] + (eval-string* sci-ctx expression))] (when (some? res) (if-let [pr-f (cond shell-out println edn-out prn)] @@ -424,7 +423,7 @@ Everything after that is bound to *command-line-args*.")) (pr-f res)) (prn res)))) 0]] (if stream? - (recur (read-next *in*)) + (recur) res))))) (catch Throwable e (error-handler* e verbose?))) From 962eefcc76ba64143da17727a8edef793920f1e5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 23:11:14 +0100 Subject: [PATCH 096/264] Move disabling pipe handler to pipe ns --- src/babashka/impl/pipe_signal_handler.clj | 11 ++++++----- src/babashka/main.clj | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/babashka/impl/pipe_signal_handler.clj b/src/babashka/impl/pipe_signal_handler.clj index aee99151..c46a10e1 100644 --- a/src/babashka/impl/pipe_signal_handler.clj +++ b/src/babashka/impl/pipe_signal_handler.clj @@ -9,8 +9,9 @@ (identical? :PIPE @pipe-state)) (defn handle-pipe! [] - (Signal/handle - (Signal. "PIPE") - (reify SignalHandler - (handle [_ _] - (vreset! pipe-state :PIPE))))) + (when-not (= "true" (System/getenv "BABASHKA_DISABLE_PIPE_HANDLER")) + (Signal/handle + (Signal. "PIPE") + (reify SignalHandler + (handle [_ _] + (vreset! pipe-state :PIPE)))))) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 38a630aa..d77d5297 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -285,8 +285,7 @@ Everything after that is bound to *command-line-args*.")) (defn main [& args] - (when-not (Boolean/valueOf ^String (System/getenv "BABASHKA_DISABLE_PIPE_HANDLER")) - (handle-pipe!)) + (handle-pipe!) #_(binding [*out* *err*] (prn "M" (meta (get bindings 'future)))) (binding [*unrestricted* true] From bb311f5480e9e7fe34be2de6ce70832872ba6862 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 23:15:02 +0100 Subject: [PATCH 097/264] Rename env var --- README.md | 4 +++- src/babashka/impl/pipe_signal_handler.clj | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14968b21..bc9ec709 100644 --- a/README.md +++ b/README.md @@ -1106,7 +1106,9 @@ Your command line args: (1 2 3) ## Package babashka script as a AWS Lambda -AWS Lambda runtime doesn't support signals, therefore babashka has to disable handling of the SIGPIPE. This can be done by setting `BABASHKA_DISABLE_PIPE_HANDLER` to `true`. +AWS Lambda runtime doesn't support signals, therefore babashka has to disable +handling of the SIGPIPE. This can be done by setting +`BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER` to `true`. ## Thanks diff --git a/src/babashka/impl/pipe_signal_handler.clj b/src/babashka/impl/pipe_signal_handler.clj index c46a10e1..e1bf83b2 100644 --- a/src/babashka/impl/pipe_signal_handler.clj +++ b/src/babashka/impl/pipe_signal_handler.clj @@ -9,7 +9,7 @@ (identical? :PIPE @pipe-state)) (defn handle-pipe! [] - (when-not (= "true" (System/getenv "BABASHKA_DISABLE_PIPE_HANDLER")) + (when-not (= "true" (System/getenv "BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER")) (Signal/handle (Signal. "PIPE") (reify SignalHandler From 349083db3b6bc5bedfa267e9bb0a6718228e6223 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 23:18:47 +0100 Subject: [PATCH 098/264] v0.0.78 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d04aca5c..009d3772 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.78-SNAPSHOT \ No newline at end of file +0.0.78 \ No newline at end of file From ac027878a5c7a629fb81743953caf9163a8d54d5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Mar 2020 23:41:59 +0100 Subject: [PATCH 099/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index b76f49a4..009d3772 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.77 +0.0.78 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 009d3772..75afeb80 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.78 \ No newline at end of file +0.0.79-SNAPSHOT \ No newline at end of file From d9b2610eaebdcc828315a29b9febf811386bfe83 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Mar 2020 11:47:02 +0100 Subject: [PATCH 100/264] Add java.io.FileReader (#307) --- src/babashka/impl/classes.clj | 1 + test/babashka/main_test.clj | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 4a4e404a..8d2cbb66 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -21,6 +21,7 @@ java.io.InputStream java.io.IOException java.io.OutputStream + java.io.FileReader java.io.Reader java.io.StringReader java.io.StringWriter diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index eb52dcf0..28df8581 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -369,6 +369,12 @@ (deftest available-stream-test (is (= 0 (bb nil "(.available System/in)")))) +(deftest file-reader-test + (when (str/includes? (str/lower-case (System/getProperty "os.name")) "linux") + (let [v (bb nil "(slurp (io/reader (java.io.FileReader. \"/proc/loadavg\")))")] + (prn "output:" v) + (is v)))) + ;;;; Scratch (comment From e312639d040009b92e98391ed0b9edf0f98e64a2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Mar 2020 11:49:14 +0100 Subject: [PATCH 101/264] Note about binary size --- doc/dev.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev.md b/doc/dev.md index 4fefb30b..40120fef 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -53,6 +53,9 @@ Then run: Keep notes here about how adding libraries and classes to Babashka affects the binary size. +2020/03/22 Added java.io.FileReader +42025276 - 42008876 = 16kb added. + 2020/03/20 Added transit write, writer, read, reader 42004796 - 41025212 = 980kb added (305kb zipped). From 0b3a15cf817adcfaf1edf74d9fc00fc0f0bbb486 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Mar 2020 11:31:47 +0100 Subject: [PATCH 102/264] Update dev.md --- doc/dev.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev.md b/doc/dev.md index 40120fef..9d77b8fe 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -1,5 +1,7 @@ # Developing Babashka +## Clone repository + To work on Babashka itself make sure Git submodules are checked out. ``` shellsession From 7977331a45b5ca8e46dbd5a9eef85af6eb25aa86 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Mar 2020 11:33:42 +0100 Subject: [PATCH 103/264] Update dev.md --- doc/dev.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/dev.md b/doc/dev.md index 9d77b8fe..e368a96d 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -49,7 +49,13 @@ To build this project, set `$GRAALVM_HOME` to the GraalVM distribution directory Then run: - script/compile + $ script/compile + +To tweak maximum heap size: + +``` +$ BABASHKA_XMX="-J-Xmx4g" script/compile +``` ## Binary size From c5a61e4d2d0173036919a194920771eb871ce6f1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Mar 2020 11:35:10 +0100 Subject: [PATCH 104/264] Update dev.md --- doc/dev.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dev.md b/doc/dev.md index e368a96d..212ef537 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -1,5 +1,7 @@ # Developing Babashka +You need [Leiningen](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java8-19.3.1. + ## Clone repository To work on Babashka itself make sure Git submodules are checked out. @@ -14,8 +16,6 @@ To update later on: $ git submodule update --recursive ``` -You need [Leiningen](https://leiningen.org/), and for building binaries you need GraalVM. - ## REPL `lein repl` will get you a standard REPL/nREPL connection. To work on tests use `lein with-profiles +test repl`. From ff181f0e1ade069f3ac8d7684265742b36616613 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Mar 2020 11:35:34 +0100 Subject: [PATCH 105/264] Update dev.md --- doc/dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev.md b/doc/dev.md index 212ef537..6a227e4c 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -1,6 +1,6 @@ # Developing Babashka -You need [Leiningen](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java8-19.3.1. +You need [lein](https://leiningen.org/) for running JVM tests and/or producing uberjars. For building binaries you need GraalVM. Currently we use java8-19.3.1. ## Clone repository From f6be5c72c892a8ff35ea81db6db53b44fa856928 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Mar 2020 11:22:19 +0100 Subject: [PATCH 106/264] sci: require as function --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index e0d5313c..68df9af1 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit e0d5313c02d5ac62bdb4311cf41b0d565b7b6d22 +Subproject commit 68df9af1ce635435f6ea9120c817b1d457986304 From 492a26813f0ee8cd46398997f0be2abc84fbf740 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Mar 2020 22:10:15 +0100 Subject: [PATCH 107/264] sci: *print-length* --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 68df9af1..b8bd1324 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 68df9af1ce635435f6ea9120c817b1d457986304 +Subproject commit b8bd132440751a120da4e1afa928f676db27134f From 1105c4676eb8f30ced06c978e85e07d3b384f8d1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 00:27:32 +0100 Subject: [PATCH 108/264] [#310] add java.nio.file.FileSystem(s) (#311) --- doc/dev.md | 3 ++ src/babashka/impl/classes.clj | 6 +++- test/babashka/file_var_test.clj | 4 +-- test/babashka/main_test.clj | 3 ++ .../scripts/download_and_extract_zip.bb | 31 +++++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 test/babashka/scripts/download_and_extract_zip.bb diff --git a/doc/dev.md b/doc/dev.md index 6a227e4c..5bc22ec9 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -61,6 +61,9 @@ $ BABASHKA_XMX="-J-Xmx4g" script/compile Keep notes here about how adding libraries and classes to Babashka affects the binary size. +2020/03/28 Added java.nio.file.FileSystem(s) to support extracting zip files +42562284 - 42021244 = 541kb added. + 2020/03/22 Added java.io.FileReader 42025276 - 42008876 = 16kb added. diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 8d2cbb66..b4ebf827 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -56,6 +56,8 @@ java.net.URLDecoder java.nio.file.CopyOption java.nio.file.FileAlreadyExistsException + java.nio.file.FileSystem + java.nio.file.FileSystems java.nio.file.Files java.nio.file.LinkOption java.nio.file.NoSuchFileException @@ -201,7 +203,9 @@ (instance? java.security.MessageDigest v) java.security.MessageDigest (instance? java.io.InputStream v) - java.io.InputStream))))) + java.io.InputStream + (instance? java.nio.file.FileSystem v) + java.nio.file.FileSystem))))) (def class-map (gen-class-map)) diff --git a/test/babashka/file_var_test.clj b/test/babashka/file_var_test.clj index 0ab76cb9..6aeb7577 100644 --- a/test/babashka/file_var_test.clj +++ b/test/babashka/file_var_test.clj @@ -1,8 +1,8 @@ (ns babashka.file-var-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 bb [input & args] (apply tu/bb (when (some? input) (str input)) (map str args))) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 28df8581..d7172641 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -375,6 +375,9 @@ (prn "output:" v) (is v)))) +(deftest download-and-extract-test + (is (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb"))))) + ;;;; Scratch (comment diff --git a/test/babashka/scripts/download_and_extract_zip.bb b/test/babashka/scripts/download_and_extract_zip.bb new file mode 100644 index 00000000..fd2bc150 --- /dev/null +++ b/test/babashka/scripts/download_and_extract_zip.bb @@ -0,0 +1,31 @@ +(require '[clojure.java.io :as io] '[clojure.java.shell :refer [sh]] '[clojure.string :as str]) +(import '[java.net URL HttpURLConnection]) + +(set! *warn-on-reflection* true) + +(let [os-name (System/getProperty "os.name") + os-name (str/lower-case os-name) + os (cond (str/includes? os-name "linux") "linux" + (str/includes? os-name "mac") "macos" + (str/includes? os-name "win") "windows") + tmp-dir (System/getProperty "java.io.tmpdir") + zip-file (io/file tmp-dir "bb-0.0.78.zip") + source (URL. (format "https://github.com/borkdude/babashka/releases/download/v0.0.78/babashka-0.0.78-%s-amd64.zip" os)) + conn ^HttpURLConnection (.openConnection ^URL source)] + (.connect conn) + (with-open [is (.getInputStream conn)] + (io/copy is zip-file)) + (let [bb-file (io/file tmp-dir "bb-extracted") + fs (java.nio.file.FileSystems/newFileSystem (.toPath zip-file) nil) + to-extract (.getPath fs "bb" (into-array String []))] + (java.nio.file.Files/copy to-extract (.toPath bb-file) + ^"[Ljava.nio.file.CopyOption;" + (into-array java.nio.file.CopyOption [])) + (.setExecutable bb-file true) + (let [out (:out (sh (.getPath bb-file) "(+ 1 2 3)"))] + (.delete bb-file) + (.delete zip-file) + (println out)))) + + + From fe76cd352c5c0470e7271eddf64e5c9018e332c2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 08:29:03 +0100 Subject: [PATCH 109/264] [#312 allow .getMessage on ex-info (#313) --- src/babashka/impl/classes.clj | 6 +++--- test/babashka/main_test.clj | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index b4ebf827..cf2fc3e7 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -13,7 +13,8 @@ ;; (identical? os :mac))) (def classes - '{:all [java.io.BufferedReader + '{:all [clojure.lang.ExceptionInfo + java.io.BufferedReader java.io.BufferedWriter java.io.ByteArrayInputStream java.io.ByteArrayOutputStream @@ -112,8 +113,7 @@ :methods [borkdude.graal.LockFix ;; support for locking ] :fields [clojure.lang.PersistentQueue] - :instance-checks [clojure.lang.ExceptionInfo - clojure.lang.IObj + :instance-checks [clojure.lang.IObj clojure.lang.IEditableCollection] :custom {clojure.lang.LineNumberingPushbackReader {:allPublicConstructors true :allPublicMethods true} diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index d7172641..12c9d514 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -378,6 +378,9 @@ (deftest download-and-extract-test (is (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb"))))) +(deftest get-message-on-exception-info-test + (is "foo" (bb nil "(try (throw (ex-info \"foo\" {})) (catch Exception e (.getMessage e)))"))) + ;;;; Scratch (comment From d0e7ad3fa1603d835ceae75ac36d7f8d0d28012d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 09:52:55 +0100 Subject: [PATCH 110/264] README --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bc9ec709..966f66bf 100644 --- a/README.md +++ b/README.md @@ -862,6 +862,12 @@ user=> (hello "Alice") "Hello Alice" ``` +## Package babashka script as a AWS Lambda + +AWS Lambda runtime doesn't support signals, therefore babashka has to disable +handling of the SIGPIPE. This can be done by setting +`BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER` to `true`. + ### Blogs - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks @@ -1104,11 +1110,23 @@ $ docker run --rm script 1 2 3 Your command line args: (1 2 3) ``` -## Package babashka script as a AWS Lambda +### Extract single file from zip -AWS Lambda runtime doesn't support signals, therefore babashka has to disable -handling of the SIGPIPE. This can be done by setting -`BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER` to `true`. +``` clojure +;; given the following zip file created as follows: +;; $ echo 'contents' > file +;; $ zip zipfile.zip file +;; $ rm file +;; we extract the single file from the zip using java.nio: + +(import '[java.nio.file Files FileSystems CopyOption]) +(let [zip-file (io/file "zipfile.zip") + file (io/file "file") + fs (FileSystems/newFileSystem (.toPath zip-file) nil) + file-in-zip (.getPath fs "file" (into-array String []))] + (Files/copy file-in-zip (.toPath file) + (into-array CopyOption []))) +``` ## Thanks From 29ac221c201edf33b7d07716cd6d0e24e2da377e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 09:55:36 +0100 Subject: [PATCH 111/264] README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 966f66bf..fe344315 100644 --- a/README.md +++ b/README.md @@ -1113,11 +1113,13 @@ Your command line args: (1 2 3) ### Extract single file from zip ``` clojure -;; given the following zip file created as follows: +;; Given the following: + ;; $ echo 'contents' > file ;; $ zip zipfile.zip file ;; $ rm file -;; we extract the single file from the zip using java.nio: + +;; we extract the single file from the zip archive using java.nio: (import '[java.nio.file Files FileSystems CopyOption]) (let [zip-file (io/file "zipfile.zip") From 4263c199790131a6742c6c336f822a702686abff Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 11:20:39 +0100 Subject: [PATCH 112/264] [#308] print exception name in REPL --- src/babashka/impl/repl.clj | 8 ++++++-- test/babashka/impl/repl_test.clj | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index a2c2f302..c60b6cf9 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -11,11 +11,15 @@ [sci.impl.parser :as parser] [sci.impl.vars :as vars])) +(set! *warn-on-reflection* true) + (defn repl-caught "Default :caught hook for repl" - [e] + [^Throwable e] (sci/with-bindings {sci/out @sci/err} - (sio/println (.getMessage ^Exception e)) + (sio/println (str (.. e getClass getName) + (when-let [m (.getMessage e)] + (str ": " m)) )) (sio/flush))) (defn repl diff --git a/test/babashka/impl/repl_test.clj b/test/babashka/impl/repl_test.clj index 29a932c8..b914207b 100644 --- a/test/babashka/impl/repl_test.clj +++ b/test/babashka/impl/repl_test.clj @@ -3,8 +3,8 @@ [babashka.impl.repl :refer [start-repl!]] [clojure.string :as str] [clojure.test :as t :refer [deftest is]] - [sci.impl.opts :refer [init]] [sci.core :as sci] + [sci.impl.opts :refer [init]] [sci.impl.vars :as vars])) (set! *warn-on-reflection* true) @@ -24,6 +24,15 @@ (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))) + (deftest repl-test (assert-repl "1" "1") (assert-repl "[1 2 3]" "[1 2 3]") @@ -34,7 +43,8 @@ (assert-repl "1\n(inc *1)" "2") (assert-repl "1\n(dec *1)(+ *2 *2)" "2") (assert-repl "1\n(dec *1)(+ *2 *2)" "2") - (assert-repl "*command-line-args*" "[\"a\" \"b\" \"c\"]")) + (assert-repl "*command-line-args*" "[\"a\" \"b\" \"c\"]") + (assert-repl-error "(+ 1 nil)" "NullPointerException")) ;;;; Scratch From 1e6558d56fde5fca222fbd832fd8aa29c1731b27 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 14:36:53 +0100 Subject: [PATCH 113/264] Add notes app example --- README.md | 7 ++++ examples/notes.clj | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100755 examples/notes.clj diff --git a/README.md b/README.md index fe344315..ca5d0317 100644 --- a/README.md +++ b/README.md @@ -1130,6 +1130,13 @@ Your command line args: (1 2 3) (into-array CopyOption []))) ``` +### Notes webapp + +See +[examples/notes.clj](https://github.com/borkdude/babashka/blob/master/examples/notes.clj). This +is a variation on the +[http-server](https://github.com/borkdude/babashka/#tiny-http-server) example. + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support diff --git a/examples/notes.clj b/examples/notes.clj new file mode 100755 index 00000000..977f8e30 --- /dev/null +++ b/examples/notes.clj @@ -0,0 +1,86 @@ +#!/usr/bin/env bb + +(import (java.net ServerSocket)) +(require '[clojure.java.io :as io] + '[clojure.java.shell :refer [sh]] + '[clojure.string :as str]) + +(def debug? false) + +(def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) +(io/make-parents notes-file) + +;; ensure notes file exists +(spit notes-file "" :append true) + +;; we wait for the server to accept connections and then open a browser +(def accepting (promise)) +(future + @accepting + (sh "open" "http://localhost:8080")) + +;; hiccup-like +(defn html [v] + (cond (vector? v) + (let [tag (first v) + attrs (second v) + attrs (when (map? attrs) attrs) + elts (if attrs (nnext v) (next v)) + tag-name (name tag)] + (format "<%s%s>%s\n" tag-name (html attrs) (html elts) tag-name)) + (map? v) + (str/join "" + (map (fn [[k v]] + (format " %s=\"%s\"" (name k) v)) v)) + (seq? v) + (str/join " " (map html v)) + :else (str v))) + +;; the home page +(defn home [] + (str + "\n" + (html + (list [:head + [:title "Notes"]] + [:body + [:h1 "Notes"] + [:pre (slurp notes-file)]] + [:form {:action "/" :method "post"} + [:input {:type "text" :name "note"}] + [:input {:type "submit" :value "Submit"}]])))) + +;; run the server +(with-open [server-socket (let [s (new ServerSocket 8080)] + (deliver accepting true) + s) + client-socket (.accept server-socket)] + (loop [] + (let [out (io/writer (.getOutputStream client-socket)) + is (.getInputStream client-socket) + in (io/reader is) + response (loop [headers []] + (let [line (.readLine in)] + (if (str/blank? line) + headers + (recur (conj headers line))))) + data (let [sb (StringBuilder.)] + (loop [] + (when (.ready in) + (.append sb (char (.read in))) + (recur))) + (-> (str sb) + (java.net.URLDecoder/decode))) + _ (when debug? (println (str/join "\n" response))) + _ (when-not (str/blank? data) + (when debug? (println data)) + (let [note (str/replace data "note=" "")] + (spit notes-file (str note "\n") :append true))) + _ (when debug? (println)) + body (home)] + (.write out (format "HTTP/1.1 %s OK\r\nContent-Length: %s\r\n\r\n%s" + 200 + (count body) + body)) + (.flush out)) + (recur))) From 34f58c554eee78fbf48e750cdc8e625b92f8b7e1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 14:39:49 +0100 Subject: [PATCH 114/264] Add pic --- README.md | 2 ++ assets/notes-example.png | Bin 0 -> 34594 bytes 2 files changed, 2 insertions(+) create mode 100644 assets/notes-example.png diff --git a/README.md b/README.md index ca5d0317..2848593b 100644 --- a/README.md +++ b/README.md @@ -1137,6 +1137,8 @@ See is a variation on the [http-server](https://github.com/borkdude/babashka/#tiny-http-server) example. + + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support diff --git a/assets/notes-example.png b/assets/notes-example.png new file mode 100644 index 0000000000000000000000000000000000000000..4434ef35be7c45271a83c67102a9689e18e5957c GIT binary patch literal 34594 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 Date: Sat, 28 Mar 2020 14:40:45 +0100 Subject: [PATCH 115/264] README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2848593b..f70d14b1 100644 --- a/README.md +++ b/README.md @@ -1130,14 +1130,14 @@ Your command line args: (1 2 3) (into-array CopyOption []))) ``` -### Notes webapp +### Note taking app See [examples/notes.clj](https://github.com/borkdude/babashka/blob/master/examples/notes.clj). This is a variation on the [http-server](https://github.com/borkdude/babashka/#tiny-http-server) example. - + ## Thanks From 5f6b26e7f31abe3c92eb3d6b306d9861adbfd389 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 15:47:28 +0100 Subject: [PATCH 116/264] Notes app improvement --- examples/notes.clj | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index 977f8e30..6634ce37 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -41,14 +41,15 @@ (str "\n" (html - (list [:head - [:title "Notes"]] - [:body - [:h1 "Notes"] - [:pre (slurp notes-file)]] - [:form {:action "/" :method "post"} - [:input {:type "text" :name "note"}] - [:input {:type "submit" :value "Submit"}]])))) + [:html + [:head + [:title "Notes"]] + [:body + [:h1 "Notes"] + [:pre (slurp notes-file)] + [:form {:action "/" :method "post"} + [:input {:type "text" :name "note"}] + [:input {:type "submit" :value "Submit"}]]]]))) ;; run the server (with-open [server-socket (let [s (new ServerSocket 8080)] From d73144bd4c80f1935dc2574d585c4287eaa3362f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 20:35:03 +0100 Subject: [PATCH 117/264] Add basic-auth to notebook example (#314) --- examples/notes.clj | 130 ++++++++++++++++++++++++++++++++------------- 1 file changed, 94 insertions(+), 36 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index 6634ce37..afa3bfe8 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -5,7 +5,11 @@ '[clojure.java.shell :refer [sh]] '[clojure.string :as str]) -(def debug? false) +(def debug? true) +(def user "admin") +(def password "admin") +(def base64 (-> (.getEncoder java.util.Base64) + (.encodeToString (.getBytes (str user ":" password))))) (def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) (io/make-parents notes-file) @@ -36,20 +40,70 @@ (str/join " " (map html v)) :else (str v))) +(defn write-response [out session-id status headers content] + (let [cookie-header (str "Set-Cookie: notes-id=" session-id) + headers (str/join "\r\n" (conj headers cookie-header)) + response (str "HTTP/1.1 " status "\r\n" + (str headers "\r\n") + "Content-Length: " (if content (count content) + 0) + "\r\n\r\n" + (when content + (str content)))] + (when debug? (println response)) + (binding [*out* out] + (print response) + (flush)))) + ;; the home page -(defn home [] - (str - "\n" - (html - [:html - [:head - [:title "Notes"]] - [:body - [:h1 "Notes"] - [:pre (slurp notes-file)] - [:form {:action "/" :method "post"} - [:input {:type "text" :name "note"}] - [:input {:type "submit" :value "Submit"}]]]]))) +(defn home-response [out session-id] + (let [body (str + "\n" + (html + [:html + [:head + [:title "Notes"]] + [:body + [:h1 "Notes"] + [:pre (slurp notes-file)] + [:form {:action "/" :method "post"} + [:input {:type "text" :name "note"}] + [:input {:type "submit" :value "Submit"}]]]]))] + (write-response out session-id "200 OK" nil body))) + +(defn basic-auth-response [out session-id] + (write-response out session-id + "401 Unauthorized" + ["WWW-Authenticate: Basic realm=\"notes\""] + nil)) + +(def known-sessions + (atom #{})) + +(defn new-session! [] + (let [uuid (str (java.util.UUID/randomUUID))] + (swap! known-sessions conj uuid) + uuid)) + +(defn get-session-id [headers] + (if-let [cookie-header (first (filter #(str/starts-with? % "Cookie: ") headers))] + (let [parts (str/split cookie-header #"; ")] + (if-let [notes-id (first (filter #(str/starts-with? % "notes-id") parts))] + (str/replace notes-id "notes-id=" "") + (new-session!))) + (new-session!))) + +(defn basic-auth-header [headers] + (some #(str/starts-with? % "Basic-Auth: ") headers)) + +(def authenticated-sessions + (atom #{})) + +(defn authenticate! [session-id headers] + (or (contains? @authenticated-sessions session-id) + (when (some #(= % (str "Authorization: Basic " base64)) headers) + (swap! authenticated-sessions conj session-id) + true))) ;; run the server (with-open [server-socket (let [s (new ServerSocket 8080)] @@ -60,28 +114,32 @@ (let [out (io/writer (.getOutputStream client-socket)) is (.getInputStream client-socket) in (io/reader is) - response (loop [headers []] - (let [line (.readLine in)] - (if (str/blank? line) - headers - (recur (conj headers line))))) - data (let [sb (StringBuilder.)] - (loop [] - (when (.ready in) - (.append sb (char (.read in))) - (recur))) - (-> (str sb) - (java.net.URLDecoder/decode))) + [_req & headers :as response] + (loop [headers []] + (let [line (.readLine in)] + (if (str/blank? line) + headers + (recur (conj headers line))))) + session-id (get-session-id headers) + form-data (let [sb (StringBuilder.)] + (loop [] + (when (.ready in) + (.append sb (char (.read in))) + (recur))) + (-> (str sb) + (java.net.URLDecoder/decode))) _ (when debug? (println (str/join "\n" response))) - _ (when-not (str/blank? data) - (when debug? (println data)) - (let [note (str/replace data "note=" "")] + _ (when-not (str/blank? form-data) + (when debug? (println form-data)) + (let [note (str/replace form-data "note=" "")] (spit notes-file (str note "\n") :append true))) - _ (when debug? (println)) - body (home)] - (.write out (format "HTTP/1.1 %s OK\r\nContent-Length: %s\r\n\r\n%s" - 200 - (count body) - body)) - (.flush out)) + _ (when debug? (println))] + (cond + ;; if we didn't see this session before, we want the user to re-authenticate + (not (contains? @known-sessions session-id)) + (let [uuid (new-session!)] + (basic-auth-response out uuid)) + (not (authenticate! session-id headers)) + (basic-auth-response out session-id) + :else (home-response out session-id))) (recur))) From 1babeb0d3c91106c28c1305036febce153787886 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Mar 2020 20:39:00 +0100 Subject: [PATCH 118/264] README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f70d14b1..a28fcd6a 100644 --- a/README.md +++ b/README.md @@ -1135,7 +1135,8 @@ Your command line args: (1 2 3) See [examples/notes.clj](https://github.com/borkdude/babashka/blob/master/examples/notes.clj). This is a variation on the -[http-server](https://github.com/borkdude/babashka/#tiny-http-server) example. +[http-server](https://github.com/borkdude/babashka/#tiny-http-server) +example. If you get prompted with a login, use `admin`/`admin`. From 3c6c0090960c61965743a4636aa60887f3bf2ed8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 11:00:07 +0200 Subject: [PATCH 119/264] Upgrade to GraalVM 19.3.1 (#316) --- .circleci/config.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c86cb6af..c9c105ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,7 +67,7 @@ jobs: working_directory: ~/repo environment: LEIN_ROOT: "true" - GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0 + GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.1 BABASHKA_PLATFORM: linux # used in release script BABASHKA_TEST_ENV: native steps: @@ -99,9 +99,9 @@ jobs: name: Download GraalVM command: | cd ~ - if ! [ -d graalvm-ce-java8-19.3.0 ]; then - curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-linux-amd64-19.3.0.tar.gz - tar xzf graalvm-ce-java8-linux-amd64-19.3.0.tar.gz + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz fi - run: name: Build binary @@ -120,7 +120,7 @@ jobs: - save_cache: paths: - ~/.m2 - - ~/graalvm-ce-java8-19.3.0 + - ~/graalvm-ce-java8-19.3.1 key: linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }} - store_artifacts: path: /tmp/release @@ -135,7 +135,7 @@ jobs: working_directory: ~/repo environment: LEIN_ROOT: "true" - GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0 + GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.1 BABASHKA_PLATFORM: linux-static # used in release script BABASHKA_TEST_ENV: native BABASHKA_STATIC: true @@ -168,9 +168,9 @@ jobs: name: Download GraalVM command: | cd ~ - if ! [ -d graalvm-ce-java8-19.3.0 ]; then - curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-linux-amd64-19.3.0.tar.gz - tar xzf graalvm-ce-java8-linux-amd64-19.3.0.tar.gz + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz fi - run: name: Build binary @@ -189,7 +189,7 @@ jobs: - save_cache: paths: - ~/.m2 - - ~/graalvm-ce-java8-19.3.0 + - ~/graalvm-ce-java8-19.3.1 key: linux-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }} - store_artifacts: path: /tmp/release @@ -202,7 +202,7 @@ jobs: macos: xcode: "9.0" environment: - GRAALVM_HOME: /Users/distiller/graalvm-ce-java8-19.3.0/Contents/Home + GRAALVM_HOME: /Users/distiller/graalvm-ce-java8-19.3.1/Contents/Home BABASHKA_PLATFORM: macos # used in release script BABASHKA_TEST_ENV: native steps: @@ -228,9 +228,9 @@ jobs: command: | cd ~ ls -la - if ! [ -d graalvm-ce-java8-19.3.0 ]; then - curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.0/graalvm-ce-java8-darwin-amd64-19.3.0.tar.gz - tar xzf graalvm-ce-java8-darwin-amd64-19.3.0.tar.gz + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-darwin-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-darwin-amd64-19.3.1.tar.gz fi - run: name: Build binary @@ -249,7 +249,7 @@ jobs: - save_cache: paths: - ~/.m2 - - ~/graalvm-ce-java8-19.3.0 + - ~/graalvm-ce-java8-19.3.1 key: mac-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }} - store_artifacts: path: /tmp/release From 308238d8d1af0035ecb856438ee2c2e4c254d5a7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 11:55:50 +0200 Subject: [PATCH 120/264] Add link to talk --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a28fcd6a..1b70574b 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,11 @@ may be a better fit, since the performance of Clojure on the JVM outweighs its startup time penalty. Read more about the differences with Clojure [here](#differences-with-clojure). +Watch the talk: + +[![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) + + ## Quickstart ``` shellsession From 3be93ed4f471e59aaf7183aa6a66bb3ca8014e1c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 11:59:50 +0200 Subject: [PATCH 121/264] README --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1b70574b..d09ba7c8 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,16 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas @laheadle on Clojurians Slack -The sweet spot for babashka is executing Clojure expressions or scripts in the -same space where you would use Bash. +## Introduction + +The main idea behind babashka is to leverage Clojure in places where you would +be using bash otherwise. As one user described it: > I’m quite at home in Bash most of the time, but there’s a substantial grey area of things that are too complicated to be simple in bash, but too simple to be worth writing a clj/s script for. Babashka really seems to hit the sweet spot for those cases. -## Goals +### Goals * Low latency Clojure scripting alternative to JVM Clojure. * Easy installation: grab the self-contained binary and run. No JVM needed. @@ -36,7 +38,7 @@ As one user described it: Also see the [slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020) of the Babashka talk at ClojureD 2020 (video coming soon). -## Non-goals +### Non-goals * Performance1 * Provide a mixed Clojure/Bash DSL (see portability). @@ -50,7 +52,10 @@ may be a better fit, since the performance of Clojure on the JVM outweighs its startup time penalty. Read more about the differences with Clojure [here](#differences-with-clojure). -Watch the talk: + +### Talk + +To get an overview of babashka, you can watch this talk: [![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) From 97144a08510cc087beca95a6cea48e141fd7f377 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 12:13:14 +0200 Subject: [PATCH 122/264] README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d09ba7c8..e3c14d34 100644 --- a/README.md +++ b/README.md @@ -872,6 +872,15 @@ user=> (hello "Alice") "Hello Alice" ``` +#### [babashka lambda layer](https://github.com/dainiusjocas/babashka-lambda-layer) + +Babashka Lambda runtime packaged as a Lambda layer. + +#### [Release on push Github action](https://github.com/rymndhng/release-on-push-action) + +Github Action to create a git tag + release when pushed to master. Written in +babashka. + ## Package babashka script as a AWS Lambda AWS Lambda runtime doesn't support signals, therefore babashka has to disable From af8c786c3153acd6dcb2d0b3b9ecc9771a0d1eb5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 13:05:27 +0200 Subject: [PATCH 123/264] emit binary size to slack --- .circleci/script/publish_artifact.clj | 44 +++++++++++++++++---------- .circleci/script/release | 2 ++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/.circleci/script/publish_artifact.clj b/.circleci/script/publish_artifact.clj index 1b5f5b74..6b0a75e9 100755 --- a/.circleci/script/publish_artifact.clj +++ b/.circleci/script/publish_artifact.clj @@ -1,23 +1,35 @@ -(require '[clojure.java.shell :refer [sh]] +(require '[cheshire.core :refer [generate-string]] '[clojure.java.io :as io] - '[cheshire.core :refer [generate-string]] + '[clojure.java.shell :refer [sh]] '[clojure.string :as str]) (def channel "#babashka_circleci_builds") #_(def channel "#_test") (def babashka-version (str/trim (slurp (io/file "resources" "BABASHKA_VERSION")))) - -(def text (format "[%s - %s@%s]: https://%s-201467090-gh.circle-artifacts.com/0/release/babashka-%s-%s-amd64.zip" - (System/getenv "BABASHKA_PLATFORM") - (System/getenv "CIRCLE_BRANCH") - (System/getenv "CIRCLE_SHA1") - (System/getenv "CIRCLE_BUILD_NUM") - babashka-version - (System/getenv "BABASHKA_PLATFORM"))) - (def slack-hook-url (System/getenv "SLACK_HOOK_URL")) -(when slack-hook-url - (let [json (generate-string {:username "borkdude" - :channel channel - :text text})] - (sh "curl" "-X" "POST" "-H" "Content-Type: application/json" "-d" json slack-hook-url))) + +(defn slack! [text] + (when slack-hook-url + (let [json (generate-string {:username "borkdude" + :channel channel + :text text})] + (sh "curl" "-X" "POST" "-H" "Content-Type: application/json" "-d" json slack-hook-url)))) + +(def release-text (format "[%s - %s@%s]: https://%s-201467090-gh.circle-artifacts.com/0/release/babashka-%s-%s-amd64.zip" + (System/getenv "BABASHKA_PLATFORM") + (System/getenv "CIRCLE_BRANCH") + (System/getenv "CIRCLE_SHA1") + (System/getenv "CIRCLE_BUILD_NUM") + babashka-version + (System/getenv "BABASHKA_PLATFORM"))) + +(slack! release-text) + +(def binary-size-text + (format "[%s - %s@%s] binary size: %s" + (System/getenv "BABASHKA_PLATFORM") + (System/getenv "CIRCLE_BRANCH") + (System/getenv "CIRCLE_SHA1") + (slurp (io/file "/tmp/bb_size/size")))) + +(slack! binary-size-text) diff --git a/.circleci/script/release b/.circleci/script/release index 2d32f514..5e6325bf 100755 --- a/.circleci/script/release +++ b/.circleci/script/release @@ -8,6 +8,8 @@ cp bb /tmp/release VERSION=$(cat resources/BABASHKA_VERSION) cd /tmp/release +mkdir -p /tmp/bb_size +./bb '(spit "/tmp/bb_size/size" (.length (io/file "bb")))' ## release binary as zip archive From 313971d0d72c726fda2da51360a054ea8e1c0173 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 13:51:45 +0200 Subject: [PATCH 124/264] notes example: don't open browser --- examples/notes.clj | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index afa3bfe8..8ac0e4ad 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -2,7 +2,6 @@ (import (java.net ServerSocket)) (require '[clojure.java.io :as io] - '[clojure.java.shell :refer [sh]] '[clojure.string :as str]) (def debug? true) @@ -17,12 +16,6 @@ ;; ensure notes file exists (spit notes-file "" :append true) -;; we wait for the server to accept connections and then open a browser -(def accepting (promise)) -(future - @accepting - (sh "open" "http://localhost:8080")) - ;; hiccup-like (defn html [v] (cond (vector? v) @@ -107,7 +100,7 @@ ;; run the server (with-open [server-socket (let [s (new ServerSocket 8080)] - (deliver accepting true) + (println "Server started on port 8080.") s) client-socket (.accept server-socket)] (loop [] From 34d36d56bae9b3885ed83552bade04dbb7975385 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:01:30 +0200 Subject: [PATCH 125/264] Support multiple sessions --- examples/notes.clj | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index 8ac0e4ad..db24141d 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -13,9 +13,14 @@ (def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) (io/make-parents notes-file) +(def file-lock (Object.)) ;; ensure notes file exists (spit notes-file "" :append true) +(defn write-note! [note] + (locking file-lock + (spit notes-file (str note "\n") :append true))) + ;; hiccup-like (defn html [v] (cond (vector? v) @@ -101,38 +106,40 @@ ;; run the server (with-open [server-socket (let [s (new ServerSocket 8080)] (println "Server started on port 8080.") - s) - client-socket (.accept server-socket)] + s)] (loop [] - (let [out (io/writer (.getOutputStream client-socket)) - is (.getInputStream client-socket) - in (io/reader is) - [_req & headers :as response] - (loop [headers []] - (let [line (.readLine in)] - (if (str/blank? line) - headers - (recur (conj headers line))))) - session-id (get-session-id headers) - form-data (let [sb (StringBuilder.)] - (loop [] - (when (.ready in) - (.append sb (char (.read in))) - (recur))) - (-> (str sb) - (java.net.URLDecoder/decode))) - _ (when debug? (println (str/join "\n" response))) - _ (when-not (str/blank? form-data) - (when debug? (println form-data)) - (let [note (str/replace form-data "note=" "")] - (spit notes-file (str note "\n") :append true))) - _ (when debug? (println))] - (cond - ;; if we didn't see this session before, we want the user to re-authenticate - (not (contains? @known-sessions session-id)) - (let [uuid (new-session!)] - (basic-auth-response out uuid)) - (not (authenticate! session-id headers)) - (basic-auth-response out session-id) - :else (home-response out session-id))) + (let [client-socket (.accept server-socket)] + (future + (with-open [conn client-socket] + (let [out (io/writer (.getOutputStream conn)) + is (.getInputStream conn) + in (io/reader is) + [_req & headers :as response] + (loop [headers []] + (let [line (.readLine in)] + (if (str/blank? line) + headers + (recur (conj headers line))))) + session-id (get-session-id headers) + form-data (let [sb (StringBuilder.)] + (loop [] + (when (.ready in) + (.append sb (char (.read in))) + (recur))) + (-> (str sb) + (java.net.URLDecoder/decode))) + _ (when debug? (println (str/join "\n" response))) + _ (when-not (str/blank? form-data) + (when debug? (println form-data)) + (let [note (str/replace form-data "note=" "")] + (write-note! note))) + _ (when debug? (println))] + (cond + ;; if we didn't see this session before, we want the user to re-authenticate + (not (contains? @known-sessions session-id)) + (let [uuid (new-session!)] + (basic-auth-response out uuid)) + (not (authenticate! session-id headers)) + (basic-auth-response out session-id) + :else (home-response out session-id)))))) (recur))) From 22ea4886667c4a7fe44e5d7483531075fcec9c4d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:10:53 +0200 Subject: [PATCH 126/264] notes app: ensure file exists --- examples/notes.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index db24141d..fa126e2d 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -12,10 +12,9 @@ (def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) (io/make-parents notes-file) - +;; ensure file exists +(.createNewFile notes-file) (def file-lock (Object.)) -;; ensure notes file exists -(spit notes-file "" :append true) (defn write-note! [note] (locking file-lock From 61939f88c919d024f2e0b80844fd8445ed60e133 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:16:12 +0200 Subject: [PATCH 127/264] notes example: add logging --- examples/notes.clj | 69 +++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index fa126e2d..3291bfab 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -109,36 +109,41 @@ (loop [] (let [client-socket (.accept server-socket)] (future - (with-open [conn client-socket] - (let [out (io/writer (.getOutputStream conn)) - is (.getInputStream conn) - in (io/reader is) - [_req & headers :as response] - (loop [headers []] - (let [line (.readLine in)] - (if (str/blank? line) - headers - (recur (conj headers line))))) - session-id (get-session-id headers) - form-data (let [sb (StringBuilder.)] - (loop [] - (when (.ready in) - (.append sb (char (.read in))) - (recur))) - (-> (str sb) - (java.net.URLDecoder/decode))) - _ (when debug? (println (str/join "\n" response))) - _ (when-not (str/blank? form-data) - (when debug? (println form-data)) - (let [note (str/replace form-data "note=" "")] - (write-note! note))) - _ (when debug? (println))] - (cond - ;; if we didn't see this session before, we want the user to re-authenticate - (not (contains? @known-sessions session-id)) - (let [uuid (new-session!)] - (basic-auth-response out uuid)) - (not (authenticate! session-id headers)) - (basic-auth-response out session-id) - :else (home-response out session-id)))))) + (try + (/ 1 0) + (with-open [conn client-socket] + (let [out (io/writer (.getOutputStream conn)) + is (.getInputStream conn) + in (io/reader is) + [_req & headers :as response] + (loop [headers []] + (let [line (.readLine in)] + (if (str/blank? line) + headers + (recur (conj headers line))))) + session-id (get-session-id headers) + form-data (let [sb (StringBuilder.)] + (loop [] + (when (.ready in) + (.append sb (char (.read in))) + (recur))) + (-> (str sb) + (java.net.URLDecoder/decode))) + _ (when debug? (println (str/join "\n" response))) + _ (when-not (str/blank? form-data) + (when debug? (println form-data)) + (let [note (str/replace form-data "note=" "")] + (write-note! note))) + _ (when debug? (println))] + (cond + ;; if we didn't see this session before, we want the user to re-authenticate + (not (contains? @known-sessions session-id)) + (let [uuid (new-session!)] + (basic-auth-response out uuid)) + (not (authenticate! session-id headers)) + (basic-auth-response out session-id) + :else (home-response out session-id)))) + (catch Throwable t + (binding [*err* *out*] + (println t)))))) (recur))) From 7837700452ab50399c70cd145d1949bca5cb1e9e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:19:42 +0200 Subject: [PATCH 128/264] notes example --- examples/notes.clj | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index 3291bfab..aff250e9 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -109,9 +109,8 @@ (loop [] (let [client-socket (.accept server-socket)] (future - (try - (/ 1 0) - (with-open [conn client-socket] + (with-open [conn client-socket] + (try (let [out (io/writer (.getOutputStream conn)) is (.getInputStream conn) in (io/reader is) @@ -142,8 +141,8 @@ (basic-auth-response out uuid)) (not (authenticate! session-id headers)) (basic-auth-response out session-id) - :else (home-response out session-id)))) - (catch Throwable t - (binding [*err* *out*] - (println t)))))) + :else (home-response out session-id))) + (catch Throwable t + (binding [*err* *out*] + (println t))))))) (recur))) From 3fd6dbd1f50bf27980144861debcf9de9e297fb4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:46:43 +0200 Subject: [PATCH 129/264] notes example --- examples/notes.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/notes.clj b/examples/notes.clj index aff250e9..8cd426e9 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -12,8 +12,6 @@ (def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) (io/make-parents notes-file) -;; ensure file exists -(.createNewFile notes-file) (def file-lock (Object.)) (defn write-note! [note] @@ -62,7 +60,8 @@ [:title "Notes"]] [:body [:h1 "Notes"] - [:pre (slurp notes-file)] + [:pre (when (.exists notes-file) + (slurp notes-file))] [:form {:action "/" :method "post"} [:input {:type "text" :name "note"}] [:input {:type "submit" :value "Submit"}]]]]))] From 90fe853f15a613580e7b4e272f4fb582d3776866 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Mar 2020 14:50:57 +0200 Subject: [PATCH 130/264] notes app --- examples/notes.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notes.clj b/examples/notes.clj index 8cd426e9..c23769ef 100755 --- a/examples/notes.clj +++ b/examples/notes.clj @@ -11,11 +11,11 @@ (.encodeToString (.getBytes (str user ":" password))))) (def notes-file (io/file (System/getProperty "user.home") ".notes" "notes.txt")) -(io/make-parents notes-file) (def file-lock (Object.)) (defn write-note! [note] (locking file-lock + (io/make-parents notes-file) (spit notes-file (str note "\n") :append true))) ;; hiccup-like From 300b293fbc52e1b2a0f7ad90b3af54c7e138700c Mon Sep 17 00:00:00 2001 From: Jeroen van Dijk Date: Sun, 29 Mar 2020 16:07:30 +0200 Subject: [PATCH 131/264] GitHub Actions build script (#291) --- .github/workflows/deploy.yml | 176 +++++++++++++++++++++++++++++++++++ script/compile | 53 +++++++++-- 2 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..599a9a69 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,176 @@ +name: deploy + +# on: +# push: +# tags: +# - "*.*.*" + +on: [push + # , pull_request + ] + +jobs: + uberjar: + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - name: Parse Ref + id: parse-ref + run: | + export VERSION="$(echo $GITHUB_SHA | head -c 7)" + echo "##[set-output name=version;]${VERSION}" + echo "##[set-output name=name;]babashka-${VERSION}" + + - name: Cache deps + uses: actions/cache@v1 + id: cache-deps + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} # Other deps files? + restore-keys: | + ${{ runner.os }}-maven- + + - name: Fetch deps + if: steps.cache-deps.outputs.cache-hit != 'true' + run: | + lein deps + + - name: Build into uberjar + run: | + echo ${{ steps.parse-ref.outputs.version }} > resources/BABASHKA_VERSION + lein uberjar + + - uses: actions/upload-artifact@v1 + with: + path: target/${{ steps.parse-ref.outputs.name }}-standalone.jar + name: jar + + - name: reflection.json + run: | + lein with-profiles +reflection run + + - uses: actions/upload-artifact@v1 + with: + name: reflection.json + path: reflection.json + + # Initial task to compile a JAR, store as a pipeline artifact to be used by + # downstream builders. + native-image-linux: + needs: [uberjar] + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - uses: actions/download-artifact@v1 + with: + name: jar + path: . + + - uses: actions/download-artifact@v1 + with: + name: reflection.json + path: . + + - name: Parse Ref + id: parse-ref + run: | + export VERSION="$(echo $GITHUB_SHA | head -c 7)" + export BASE=babashka-${VERSION} + echo "##[set-output name=base;]${BASE}" + echo "##[set-output name=name;]${BASE}-linux" + + # Look up at releases here https://github.com/graalvm/graalvm-ce-builds/releases + - name: Prepare GraalVM + uses: DeLaGuardo/setup-graalvm@2.0 + with: + graalvm-version: "20.0.0.java8" + # Newer versions don't work yet + # graalvm-version: "19.3.1.java8" + # graalvm-version: "20.0.0.java8" + + - name: Build Linux native image + run: | + echo "native image at $(which gu)" + export GRAALVM_DEBUG=1 # Seems to work (not ideal, can give runtime errors) + export JAR=${{ steps.parse-ref.outputs.base }}-standalone.jar + export BINARY_NAME=${{ steps.parse-ref.outputs.name }} + script/compile + + - name: Test binary + run: | + export BINARY=./${{ steps.parse-ref.outputs.name }} + $BINARY -e '(println "OK")' + + - run: tar -cvzf ${{ steps.parse-ref.outputs.name }}.tgz ./${{ steps.parse-ref.outputs.name }} + + - uses: actions/upload-artifact@v1 + with: + path: ${{ steps.parse-ref.outputs.name }}.tgz + name: binary-linux + + + # Use GraalVM on macOS to convert JAR to a native macOS binary + native-image-mac: + needs: [uberjar, native-image-linux] # Make it wait for a succesful Linux build as that one runs faster (because of a queue somewhere?). Is also more expensive. + runs-on: macOS-latest + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - uses: actions/download-artifact@v1 + with: + name: jar + path: . + + - uses: actions/download-artifact@v1 + with: + name: reflection.json + path: . + + - name: Parse Ref + id: parse-ref + run: | + export VERSION="$(echo $GITHUB_SHA | head -c 7)" + export BASE=babashka-${VERSION} + echo "##[set-output name=base;]${BASE}" + echo "##[set-output name=name;]${BASE}-mac" + + # Look up at releases here https://github.com/graalvm/graalvm-ce-builds/releases + - name: Prepare GraalVM + uses: DeLaGuardo/setup-graalvm@2.0 + with: + graalvm-version: "20.0.0.java8" + # graalvm-version: "19.3.1.java8" + + - name: Build Mac native image + run: | + echo "native image at $(which gu)" + export GRAALVM_DEBUG=1 # Seems to work (not ideal, can give runtime errors) + export JAR=${{ steps.parse-ref.outputs.base }}-standalone.jar + export BINARY_NAME=${{ steps.parse-ref.outputs.name }} + script/compile + + - name: Test binary + run: | + export BINARY=./${{ steps.parse-ref.outputs.name }} + $BINARY -e '(println "OK")' + + - run: tar -cvzf ${{ steps.parse-ref.outputs.name }}.tgz ./${{ steps.parse-ref.outputs.name }} + + - uses: actions/upload-artifact@v1 + with: + path: ${{ steps.parse-ref.outputs.name }}.tgz + name: binary-mac diff --git a/script/compile b/script/compile index fb040df0..4a1707f7 100755 --- a/script/compile +++ b/script/compile @@ -2,16 +2,40 @@ set -eo pipefail -if [ -z "$GRAALVM_HOME" ]; then - echo "Please set GRAALVM_HOME" - exit 1 +GU=`which gu` || true + +if [ -z "$GU" ]; then + if [ -z "$GRAALVM_HOME" ]; then + echo "Please set GRAALVM_HOME" + exit 1 + fi + + GU="$GRAALVM_HOME/bin/gu" +else + GRAALVM_HOME=`echo $GU | sed -e "s/\/bin\/gu$//"` fi if [ -z "$BABASHKA_XMX" ]; then export BABASHKA_XMX="-J-Xmx3g" fi -"$GRAALVM_HOME/bin/gu" install native-image || true +NATIVE_IMAGE=`which native-image` || true + +if [ -z "$NATIVE_IMAGE" ]; then + $GU install native-image || true + + NATIVE_IMAGE=`which native-image` || true + + if [ -z "$NATIVE_IMAGE" ]; then + if [ -z "$GRAALVM_HOME" ]; then + echo "Please set GRAALVM_HOME" + exit 1 + fi + NATIVE_IMAGE="$GRAALVM_HOME/bin/native-image" + fi +fi + +## --- THE ACTUAL SCRIPT --- BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) @@ -19,11 +43,16 @@ export JAVA_HOME=$GRAALVM_HOME $GRAALVM_HOME/bin/javac -cp $GRAALVM_HOME/jre/lib/svm/builder/svm.jar resources/CutOffCoreServicesDependencies.java -lein with-profiles +reflection do run -lein do clean, uberjar +if [ -z "$JAR" ]; then + lein with-profiles +reflection do run + lein do clean, uberjar + JAR=${JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"} +fi -args=( -jar target/babashka-$BABASHKA_VERSION-standalone.jar \ - -H:Name=bb \ +BINARY_NAME=${BINARY_NAME:-"bb"} + +args=( -jar $JAR \ + -H:Name=$BINARY_NAME \ -H:+ReportExceptionStackTraces \ -J-Dclojure.spec.skip-macros=true \ -J-Dclojure.compiler.direct-linking=true \ @@ -48,4 +77,10 @@ fi $GRAALVM_HOME/bin/native-image "${args[@]}" -lein clean +LEIN=`which lein` || true + +if [ -z "$LEIN" ]; then + echo "nothing to clean" +else + lein clean +fi \ No newline at end of file From 548ffa851b37c9f0e28e4ae542b9fb72779128c5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Mar 2020 20:29:08 +0200 Subject: [PATCH 132/264] Github actions enhancements (#319) --- .circleci/config.yml | 4 +- .github/script/deploy | 8 + .github/script/docker | 36 ++ .github/workflows/build.yml | 345 ++++++++++++++++++ .github/workflows/deploy.yml | 176 --------- script/compile | 56 +-- {.circleci/script => script}/install-clojure | 2 +- .../script => script}/install-leiningen | 7 +- script/test | 3 + 9 files changed, 413 insertions(+), 224 deletions(-) create mode 100755 .github/script/deploy create mode 100755 .github/script/docker create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/deploy.yml rename {.circleci/script => script}/install-clojure (95%) rename {.circleci/script => script}/install-leiningen (50%) diff --git a/.circleci/config.yml b/.circleci/config.yml index c9c105ad..191af3d8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -218,11 +218,11 @@ jobs: - run: name: Install Clojure command: | - .circleci/script/install-clojure /usr/local + script/install-clojure /usr/local - run: name: Install Leiningen command: | - .circleci/script/install-leiningen + script/install-leiningen - run: name: Download GraalVM command: | diff --git a/.github/script/deploy b/.github/script/deploy new file mode 100755 index 00000000..31c8a147 --- /dev/null +++ b/.github/script/deploy @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +if [ -z "$GITHUB_HEAD_REF" ] && [ "${GITHUB_REF##*/}" = "master" ] +then + lein deploy clojars +fi + +exit 0; diff --git a/.github/script/docker b/.github/script/docker new file mode 100755 index 00000000..a0121d94 --- /dev/null +++ b/.github/script/docker @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -eo pipefail + +image_name="borkdude/babashka" +image_tag=$(cat resources/BABASHKA_VERSION) +latest_tag="latest" + +if [[ $image_tag =~ SNAPSHOT$ ]] +then + echo "This is a snapshot version" + snapshot="true" +else + echo "This is a non-snapshot version" + snapshot="false" +fi + +if [ -z "$GITHUB_HEAD_REF" ] && [ "${GITHUB_REF##*/}" = "master" ] +then + echo "Building Docker image $image_name:$image_tag" + echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin + docker build -t "$image_name" . + docker tag "$image_name:$latest_tag" "$image_name:$image_tag" + # we only update latest when it's not a SNAPSHOT version + if [ "false" = "$snapshot" ]; then + echo "Pushing image $image_name:$latest_tag" + docker push "$image_name:$latest_tag" + fi + # we update the version tag, even if it's a SNAPSHOT version + echo "Pushing image $image_name:$image_tag" + docker push "$image_name:$image_tag" +else + echo "Not publishing Docker image" +fi + +exit 0; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..ae444cf3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,345 @@ +name: build + +on: [push + , pull_request + ] + +jobs: + + scratch: + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - name: Scratch + run: | + echo "Scratch" + + jvm: + # ubuntu 18.04 comes with lein + java8 installed + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - name: Cache deps + uses: actions/cache@v1 + id: cache-deps + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Fetch deps + if: steps.cache-deps.outputs.cache-hit != 'true' + run: | + lein deps + + - name: Run tests + run: | + script/test + + - name: Test libraries + run: | + sudo script/install-clojure + script/run_lib_tests + + - name: Build uberjar + run: | + lein with-profiles +reflection do run + lein do clean, uberjar + + - name: Babashka version + id: babashka-version + run: | + BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) + echo "##[set-output name=version;]${BABASHKA_VERSION}" + + - name: Reflection artifact + run: | + cp reflection.json babashka-${{ steps.babashka-version.outputs.version }}-reflection.json + + - uses: actions/upload-artifact@v1 + with: + name: jar + path: target/babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar + + - uses: actions/upload-artifact@v1 + with: + name: reflection.json + path: babashka-${{ steps.babashka-version.outputs.version }}-reflection.json + + linux: + needs: [jvm] + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - uses: actions/download-artifact@v1 + with: + name: jar + path: . + + - uses: actions/download-artifact@v1 + with: + name: reflection.json + path: . + + - name: Cache deps + uses: actions/cache@v1 + id: cache-deps + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Cache GraalVM + uses: actions/cache@v1 + id: cache-graalvm + with: + path: ~/graalvm-ce-java8-19.3.1 + key: ${{ runner.os }}-graalvm-19.3.1 + restore-keys: | + ${{ runner.os }}-graalvm-19.3.1 + + - name: Download GraalVM + run: | + cd ~ + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + fi + + - name: Babashka version + id: babashka-version + run: | + BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) + echo "##[set-output name=version;]${BABASHKA_VERSION}" + + - name: Build Linux native image + run: | + export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar + export BABASHKA_XMX="-J-Xmx6g" + export GRAALVM_HOME="$HOME/graalvm-ce-java8-19.3.1" + cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json + script/compile + + - name: Test binary + run: | + BABASHKA_TEST_ENV=native script/test + + - name: Install clojure + run: | + sudo script/install-clojure /usr/local + + - name: Test libraries + run: | + BABASHKA_TEST_ENV=native script/run_lib_tests + + - uses: actions/upload-artifact@v1 + with: + path: bb + name: babashka-${{ steps.babashka-version.outputs.version }}-linux-amd64.zip + + linux-static: + needs: [jvm] + runs-on: ubuntu-16.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - uses: actions/download-artifact@v1 + with: + name: jar + path: . + + - uses: actions/download-artifact@v1 + with: + name: reflection.json + path: . + + - name: Cache deps + uses: actions/cache@v1 + id: cache-deps + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Cache GraalVM + uses: actions/cache@v1 + id: cache-graalvm + with: + path: ~/graalvm-ce-java8-19.3.1 + key: ${{ runner.os }}-graalvm-19.3.1 + restore-keys: | + ${{ runner.os }}-graalvm-19.3.1 + + - name: Download GraalVM + run: | + cd ~ + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + fi + + - name: Babashka version + id: babashka-version + run: | + BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) + echo "##[set-output name=version;]${BABASHKA_VERSION}" + + - name: Build Linux native image + run: | + export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar + export BABASHKA_XMX="-J-Xmx6g" + export GRAALVM_HOME="$HOME/graalvm-ce-java8-19.3.1" + export BABASHKA_STATIC=true + cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json + script/compile + + - name: Test binary + run: | + ./bb '(+ 1 2 3)' + BABASHKA_TEST_ENV=native script/test + + - name: Install clojure + run: | + sudo script/install-clojure + + - name: Test libraries + run: | + BABASHKA_TEST_ENV=native script/run_lib_tests + + - uses: actions/upload-artifact@v1 + with: + path: bb + name: babashka-${{ steps.babashka-version.outputs.version }}-linux-static-amd64.zip + + mac: + needs: [jvm] + runs-on: macOS-latest + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - uses: actions/download-artifact@v1 + with: + name: jar + path: . + + - uses: actions/download-artifact@v1 + with: + name: reflection.json + path: . + + - name: Cache GraalVM + uses: actions/cache@v1 + id: cache-graalvm + with: + path: ~/graalvm-ce-java8-19.3.1 + key: ${{ runner.os }}-graalvm-19.3.1 + restore-keys: | + ${{ runner.os }}-graalvm-19.3.1 + + - name: Download GraalVM + run: | + cd ~ + if ! [ -d graalvm-ce-java8-19.3.1 ]; then + curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-darwin-amd64-19.3.1.tar.gz + tar xzf graalvm-ce-java8-darwin-amd64-19.3.1.tar.gz + fi + + - name: Babashka version + id: babashka-version + run: | + BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) + echo "##[set-output name=version;]${BABASHKA_VERSION}" + + - name: Build macOS native image + run: | + export BABASHKA_JAR=babashka-${{ steps.babashka-version.outputs.version }}-standalone.jar + export BABASHKA_XMX="-J-Xmx6g" + export GRAALVM_HOME="$HOME/graalvm-ce-java8-19.3.1/Contents/Home" + cp babashka-${{ steps.babashka-version.outputs.version }}-reflection.json reflection.json + script/compile + + - name: Test binary + run: | + sudo script/install-leiningen + BABASHKA_TEST_ENV=native script/test + + - name: Test libraries + run: | + sudo script/install-clojure + BABASHKA_TEST_ENV=native script/run_lib_tests + + - uses: actions/upload-artifact@v1 + with: + path: bb + name: babashka-${{ steps.babashka-version.outputs.version }}-macos-amd64.zip + + deploy: + needs: [jvm, linux, linux-static, mac] + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - name: Cache deps + uses: actions/cache@v1 + id: cache-deps + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Deploy + env: + CLOJARS_USER: "${{ secrets.CLOJARS_USER }}" + CLOJARS_PASS: "${{ secrets.CLOJARS_PASS }}" + run: | + .github/script/deploy + + docker: + needs: [jvm, linux, linux-static, mac] + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + runs-on: ubuntu-18.04 + steps: + - name: Git checkout + uses: actions/checkout@v1 + with: + fetch-depth: 1 + submodules: 'true' + + - name: Docker build + env: + DOCKERHUB_USER: "${{ secrets.DOCKERHUB_USER }}" + DOCKERHUB_PASS: "${{ secrets.DOCKERHUB_PASS }}" + run: | + .github/script/docker diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 599a9a69..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,176 +0,0 @@ -name: deploy - -# on: -# push: -# tags: -# - "*.*.*" - -on: [push - # , pull_request - ] - -jobs: - uberjar: - runs-on: ubuntu-18.04 - steps: - - name: Git checkout - uses: actions/checkout@v1 - with: - fetch-depth: 1 - submodules: 'true' - - - name: Parse Ref - id: parse-ref - run: | - export VERSION="$(echo $GITHUB_SHA | head -c 7)" - echo "##[set-output name=version;]${VERSION}" - echo "##[set-output name=name;]babashka-${VERSION}" - - - name: Cache deps - uses: actions/cache@v1 - id: cache-deps - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('project.clj') }} # Other deps files? - restore-keys: | - ${{ runner.os }}-maven- - - - name: Fetch deps - if: steps.cache-deps.outputs.cache-hit != 'true' - run: | - lein deps - - - name: Build into uberjar - run: | - echo ${{ steps.parse-ref.outputs.version }} > resources/BABASHKA_VERSION - lein uberjar - - - uses: actions/upload-artifact@v1 - with: - path: target/${{ steps.parse-ref.outputs.name }}-standalone.jar - name: jar - - - name: reflection.json - run: | - lein with-profiles +reflection run - - - uses: actions/upload-artifact@v1 - with: - name: reflection.json - path: reflection.json - - # Initial task to compile a JAR, store as a pipeline artifact to be used by - # downstream builders. - native-image-linux: - needs: [uberjar] - runs-on: ubuntu-18.04 - steps: - - name: Git checkout - uses: actions/checkout@v1 - with: - fetch-depth: 1 - submodules: 'true' - - - uses: actions/download-artifact@v1 - with: - name: jar - path: . - - - uses: actions/download-artifact@v1 - with: - name: reflection.json - path: . - - - name: Parse Ref - id: parse-ref - run: | - export VERSION="$(echo $GITHUB_SHA | head -c 7)" - export BASE=babashka-${VERSION} - echo "##[set-output name=base;]${BASE}" - echo "##[set-output name=name;]${BASE}-linux" - - # Look up at releases here https://github.com/graalvm/graalvm-ce-builds/releases - - name: Prepare GraalVM - uses: DeLaGuardo/setup-graalvm@2.0 - with: - graalvm-version: "20.0.0.java8" - # Newer versions don't work yet - # graalvm-version: "19.3.1.java8" - # graalvm-version: "20.0.0.java8" - - - name: Build Linux native image - run: | - echo "native image at $(which gu)" - export GRAALVM_DEBUG=1 # Seems to work (not ideal, can give runtime errors) - export JAR=${{ steps.parse-ref.outputs.base }}-standalone.jar - export BINARY_NAME=${{ steps.parse-ref.outputs.name }} - script/compile - - - name: Test binary - run: | - export BINARY=./${{ steps.parse-ref.outputs.name }} - $BINARY -e '(println "OK")' - - - run: tar -cvzf ${{ steps.parse-ref.outputs.name }}.tgz ./${{ steps.parse-ref.outputs.name }} - - - uses: actions/upload-artifact@v1 - with: - path: ${{ steps.parse-ref.outputs.name }}.tgz - name: binary-linux - - - # Use GraalVM on macOS to convert JAR to a native macOS binary - native-image-mac: - needs: [uberjar, native-image-linux] # Make it wait for a succesful Linux build as that one runs faster (because of a queue somewhere?). Is also more expensive. - runs-on: macOS-latest - steps: - - name: Git checkout - uses: actions/checkout@v1 - with: - fetch-depth: 1 - submodules: 'true' - - - uses: actions/download-artifact@v1 - with: - name: jar - path: . - - - uses: actions/download-artifact@v1 - with: - name: reflection.json - path: . - - - name: Parse Ref - id: parse-ref - run: | - export VERSION="$(echo $GITHUB_SHA | head -c 7)" - export BASE=babashka-${VERSION} - echo "##[set-output name=base;]${BASE}" - echo "##[set-output name=name;]${BASE}-mac" - - # Look up at releases here https://github.com/graalvm/graalvm-ce-builds/releases - - name: Prepare GraalVM - uses: DeLaGuardo/setup-graalvm@2.0 - with: - graalvm-version: "20.0.0.java8" - # graalvm-version: "19.3.1.java8" - - - name: Build Mac native image - run: | - echo "native image at $(which gu)" - export GRAALVM_DEBUG=1 # Seems to work (not ideal, can give runtime errors) - export JAR=${{ steps.parse-ref.outputs.base }}-standalone.jar - export BINARY_NAME=${{ steps.parse-ref.outputs.name }} - script/compile - - - name: Test binary - run: | - export BINARY=./${{ steps.parse-ref.outputs.name }} - $BINARY -e '(println "OK")' - - - run: tar -cvzf ${{ steps.parse-ref.outputs.name }}.tgz ./${{ steps.parse-ref.outputs.name }} - - - uses: actions/upload-artifact@v1 - with: - path: ${{ steps.parse-ref.outputs.name }}.tgz - name: binary-mac diff --git a/script/compile b/script/compile index 4a1707f7..3d1562a4 100755 --- a/script/compile +++ b/script/compile @@ -2,40 +2,16 @@ set -eo pipefail -GU=`which gu` || true - -if [ -z "$GU" ]; then - if [ -z "$GRAALVM_HOME" ]; then - echo "Please set GRAALVM_HOME" - exit 1 - fi - - GU="$GRAALVM_HOME/bin/gu" -else - GRAALVM_HOME=`echo $GU | sed -e "s/\/bin\/gu$//"` -fi - if [ -z "$BABASHKA_XMX" ]; then export BABASHKA_XMX="-J-Xmx3g" fi -NATIVE_IMAGE=`which native-image` || true - -if [ -z "$NATIVE_IMAGE" ]; then - $GU install native-image || true - - NATIVE_IMAGE=`which native-image` || true - - if [ -z "$NATIVE_IMAGE" ]; then - if [ -z "$GRAALVM_HOME" ]; then - echo "Please set GRAALVM_HOME" - exit 1 - fi - NATIVE_IMAGE="$GRAALVM_HOME/bin/native-image" - fi +if [ -z "$GRAALVM_HOME" ]; then + echo "Please set GRAALVM_HOME" + exit 1 fi -## --- THE ACTUAL SCRIPT --- +$GRAALVM_HOME/bin/gu install native-image BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) @@ -43,16 +19,16 @@ export JAVA_HOME=$GRAALVM_HOME $GRAALVM_HOME/bin/javac -cp $GRAALVM_HOME/jre/lib/svm/builder/svm.jar resources/CutOffCoreServicesDependencies.java -if [ -z "$JAR" ]; then - lein with-profiles +reflection do run - lein do clean, uberjar - JAR=${JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"} +if [ -z "$BABASHKA_JAR" ]; then + lein with-profiles +reflection do run + lein do clean, uberjar + BABASHKA_JAR=${BABASHKA_JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"} fi -BINARY_NAME=${BINARY_NAME:-"bb"} +BABASHKA_BINARY=${BABASHKA_BINARY:-"bb"} -args=( -jar $JAR \ - -H:Name=$BINARY_NAME \ +args=( -jar $BABASHKA_JAR \ + -H:Name=$BABASHKA_BINARY \ -H:+ReportExceptionStackTraces \ -J-Dclojure.spec.skip-macros=true \ -J-Dclojure.compiler.direct-linking=true \ @@ -77,10 +53,6 @@ fi $GRAALVM_HOME/bin/native-image "${args[@]}" -LEIN=`which lein` || true - -if [ -z "$LEIN" ]; then - echo "nothing to clean" -else - lein clean -fi \ No newline at end of file +if [ ! -z "$(command -v lein)" ]; then + lein clean +fi diff --git a/.circleci/script/install-clojure b/script/install-clojure similarity index 95% rename from .circleci/script/install-clojure rename to script/install-clojure index b4cb4a55..f4781ba1 100755 --- a/.circleci/script/install-clojure +++ b/script/install-clojure @@ -1,6 +1,6 @@ #!/usr/bin/env bash -install_dir=${1:-/tmp/clojure} +install_dir=${1:-/usr/local} mkdir -p "$install_dir" cd /tmp curl -O -sL https://download.clojure.org/install/clojure-tools-1.10.1.447.tar.gz diff --git a/.circleci/script/install-leiningen b/script/install-leiningen similarity index 50% rename from .circleci/script/install-leiningen rename to script/install-leiningen index fc4b11ea..92a62a41 100755 --- a/.circleci/script/install-leiningen +++ b/script/install-leiningen @@ -1,6 +1,7 @@ #!/usr/bin/env bash curl https://raw.githubusercontent.com/technomancy/leiningen/2.9.1/bin/lein > lein -sudo mkdir -p /usr/local/bin/ -sudo mv lein /usr/local/bin/lein -sudo chmod a+x /usr/local/bin/lein +mkdir -p /usr/local/bin/ +mv lein /usr/local/bin/lein +chmod a+x /usr/local/bin/lein +lein self-install diff --git a/script/test b/script/test index 58f31d5f..d6c8473b 100755 --- a/script/test +++ b/script/test @@ -3,13 +3,16 @@ set -eo pipefail BABASHKA_PRELOADS="" BABASHKA_CLASSPATH="" +echo "running tests part 1" lein test "$@" BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")' BABASHKA_PRELOADS_TEST=true +echo "running tests part 2" lein test :only babashka.main-test/preloads-test BABASHKA_PRELOADS="(require '[env-ns])" BABASHKA_CLASSPATH_TEST=true BABASHKA_CLASSPATH="test-resources/babashka/src_for_classpath_test/env" +echo "running tests part 3" lein test :only babashka.classpath-test/classpath-env-test From 63a7dd459fd0f81e8ecb76c3c7655d0d450ca489 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Mar 2020 11:05:44 +0200 Subject: [PATCH 133/264] README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e3c14d34..e5411744 100644 --- a/README.md +++ b/README.md @@ -1063,6 +1063,8 @@ bb '(let [{:keys [dependencies source-paths resource-paths]} (apply hash-map (dr jet --pretty > deps.edn ``` +A script with the same goal can be found [here](https://gist.github.com/swlkr/3f346c66410e5c60c59530c4413a248e#gistcomment-3232605). + ### Print current time in California See [examples/pst.clj](https://github.com/borkdude/babashka/blob/master/examples/pst.clj) From 5eadd61bc8c6394a8e07fa9b8bf79d950db97204 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Mar 2020 15:19:52 +0200 Subject: [PATCH 134/264] Funding.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c7fbd994..2ff623c6 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,7 +2,7 @@ github: borkdude # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: borkdude -open_collective: # Replace with a single Open Collective username +open_collective: babashka ko_fi: borkdude tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry From 270b0acd71173eed1bc1f5f4c445bb50ebc4fffc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Mar 2020 15:21:07 +0200 Subject: [PATCH 135/264] sci: updated funding --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index b8bd1324..0e011ddb 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit b8bd132440751a120da4e1afa928f676db27134f +Subproject commit 0e011ddb4d435dfebe6c9cf0547e26244d77aec7 From 85ef90015346b0a59d610e0227543ac88d43d119 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Apr 2020 21:41:49 +0200 Subject: [PATCH 136/264] babashka.curl: support :response option --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 3104d234..9fb2f75c 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 3104d234a63fca71f0d3557c5d3dc23f4fbc294f +Subproject commit 9fb2f75cc871e09075c70eae3b139c787d187d59 From 3e0ea7ac3ba1c1d0254c7882da40f6d42503bc47 Mon Sep 17 00:00:00 2001 From: Victor Bjelkholm Date: Fri, 3 Apr 2020 11:01:30 +0200 Subject: [PATCH 137/264] Add link to video from ClojureD 2020 (#323) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5411744..7ee12252 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ As one user described it: * Batteries included (tools.cli, cheshire, ...) * Library support via popular tools like the `clojure` CLI -Also see the [slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020) of the Babashka talk at ClojureD 2020 (video coming soon). +Also see the [slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020) of the Babashka talk at ClojureD 2020 ([video](https://www.youtube.com/watch?v=Nw8aN-nrdEk)). ### Non-goals From 27034effccc129645cebc886d3a1f1638715ec4e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 11:09:57 +0200 Subject: [PATCH 138/264] babasha.curl: add Github action --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 9fb2f75c..57daab01 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 9fb2f75cc871e09075c70eae3b139c787d187d59 +Subproject commit 57daab013d4108c5898a3a92fc00395a1e9da5ed From ba578626111367a9f49eb2f895057c48b818810c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 12:56:17 +0200 Subject: [PATCH 139/264] [#325] find-ns doesn't return nil for non-existing namespace --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 0e011ddb..44442c93 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 0e011ddb4d435dfebe6c9cf0547e26244d77aec7 +Subproject commit 44442c9364225703fb2d4b31ee850ba9ac2ae0f0 From f89514f416875c3464e1efd1c93757b2de487616 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 13:05:49 +0200 Subject: [PATCH 140/264] Fix test --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 44442c93..2b193fff 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 44442c9364225703fb2d4b31ee850ba9ac2ae0f0 +Subproject commit 2b193fff9499c9245d4630402491d4acf8cb7256 From 90eb43747b13c44533df842a2f083620df2e6def Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 14:20:31 +0200 Subject: [PATCH 141/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 2b193fff..bce604b2 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 2b193fff9499c9245d4630402491d4acf8cb7256 +Subproject commit bce604b2147e4877d70a3dbe532ba00b4c2b5a19 From 1c0e004f2fe20fc34080088cb7462c9b7703ac9e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 15:36:20 +0200 Subject: [PATCH 142/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index bce604b2..26944ee9 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit bce604b2147e4877d70a3dbe532ba00b4c2b5a19 +Subproject commit 26944ee9e1349fecd113ac6075bd66306ce3a6f8 From 8b90e40de463eee2ddca752100ecb4dd9b5a23bc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 3 Apr 2020 23:51:54 +0200 Subject: [PATCH 143/264] [#301] Add nREPL server (#326) --- README.md | 3 +- deps.edn | 4 +- project.clj | 3 +- src/babashka/impl/bencode.clj | 11 + src/babashka/impl/bencode/core.clj | 420 +++++++++++++++++++++++ src/babashka/impl/classes.clj | 2 + src/babashka/impl/clojure/main.clj | 5 + src/babashka/impl/clojure/stacktrace.clj | 16 +- src/babashka/impl/nrepl_server.clj | 236 +++++++++++++ src/babashka/impl/transit.clj | 1 + src/babashka/main.clj | 33 +- src/babashka/wait.clj | 4 +- test/babashka/impl/nrepl_server_test.clj | 120 +++++++ test/babashka/impl/socket_repl_test.clj | 2 +- 14 files changed, 842 insertions(+), 18 deletions(-) create mode 100644 src/babashka/impl/bencode.clj create mode 100644 src/babashka/impl/bencode/core.clj create mode 100644 src/babashka/impl/nrepl_server.clj create mode 100644 test/babashka/impl/nrepl_server_test.clj diff --git a/README.md b/README.md index 7ee12252..d366c9ab 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Check out the image on [Docker hub](https://hub.docker.com/r/borkdude/babashka/) Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] [ ( --classpath | -cp ) ] [ --uberscript ] [ ( --main | -m ) | -e | -f | - --repl | --socket-repl [:] ] + --repl | --socket-repl [:] | --nrepl-server [:] ] [ arg* ] Options: @@ -194,6 +194,7 @@ Options: -m, --main Call the -main function from namespace with args. --repl Start REPL. Use rlwrap for history. --socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666). + --nrepl-server Start nREPL server. Specify port (e.g. 1667) or host and port separated by colon (e.g. 127.0.0.1:1667). --time Print execution time before exiting. -- Stop parsing args and pass everything after -- to *command-line-args* diff --git a/deps.edn b/deps.edn index 644d698e..c09a693c 100644 --- a/deps.edn +++ b/deps.edn @@ -9,7 +9,9 @@ org.clojure/data.csv {:mvn/version "1.0.0"}, cheshire {:mvn/version "5.10.0"} fipp {:mvn/version "0.6.22"} - com.cognitect/transit-clj {:mvn/version "1.0.324"}} + com.cognitect/transit-clj {:mvn/version "1.0.324"} + ;; nrepl/bencode {:mvn/version "1.0.0"} + } :aliases {:main {:main-opts ["-m" "babashka.main"]} :profile diff --git a/project.clj b/project.clj index becb1397..8dbf52a2 100644 --- a/project.clj +++ b/project.clj @@ -19,7 +19,8 @@ [org.clojure/data.csv "1.0.0"] [cheshire "5.10.0"] [fipp "0.6.22"] - [com.cognitect/transit-clj "1.0.324"]] + [com.cognitect/transit-clj "1.0.324"] + #_[nrepl/bencode "1.0.0"]] :profiles {:test {:dependencies [[clj-commons/conch "0.9.2"] [com.clojure-goes-fast/clj-async-profiler "0.4.0"]]} :uberjar {:global-vars {*assert* false} diff --git a/src/babashka/impl/bencode.clj b/src/babashka/impl/bencode.clj new file mode 100644 index 00000000..3d452eb6 --- /dev/null +++ b/src/babashka/impl/bencode.clj @@ -0,0 +1,11 @@ +(ns babashka.impl.bencode + {:no-doc true} + (:require [babashka.impl.bencode.core :as bencode] + [sci.impl.namespaces :refer [copy-var]] + [sci.impl.vars :as vars])) + +(def tns (vars/->SciNamespace 'bencode.core nil)) + +(def bencode-namespace + {'read-bencode (copy-var bencode/read-bencode tns) + 'write-bencode (copy-var bencode/write-bencode tns)}) diff --git a/src/babashka/impl/bencode/core.clj b/src/babashka/impl/bencode/core.clj new file mode 100644 index 00000000..20e24e5b --- /dev/null +++ b/src/babashka/impl/bencode/core.clj @@ -0,0 +1,420 @@ +(ns babashka.impl.bencode.core + "A netstring and bencode implementation for Clojure." + {:author "Meikel Brandmeyer" + :no-doc true} + (:require [clojure.java.io :as io]) + (:import [java.io ByteArrayOutputStream + EOFException + InputStream + IOException + OutputStream + PushbackInputStream])) + +;; Copyright (c) Meikel Brandmeyer. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. + +;; # Motivation +;; +;; In each and every application, which contacts peer processes via some +;; communication channel, the handling of the communication channel is +;; obviously a central part of the application. Unfortunately introduces +;; handling of buffers of varying sizes often bugs in form of buffer +;; overflows and similar. +;; +;; A strong factor in this situation is of course the protocol which goes +;; over the wire. Depending on its design it might be difficult to estimate +;; the size of the input up front. This introduces more handling of message +;; buffers to accomodate for inputs of varying sizes. This is particularly +;; difficult in languages like C, where there is no bounds checking of array +;; accesses and where errors might go unnoticed for considerable amount of +;; time. +;; +;; To address these issues D. Bernstein developed the so called +;; [netstrings][net]. They are especially designed to allow easy construction +;; of the message buffers, easy and robust parsing. +;; +;; BitTorrent extended this to the [bencode][bc] protocol which also +;; includes ways to encode numbers and collections like lists or maps. +;; +;; *wire* is based on these ideas. +;; +;; [net]: http://cr.yp.to/proto/netstrings.txt +;; [bc]: http://wiki.theory.org/BitTorrentSpecification#Bencoding +;; +;; # Netstrings +;; +;; Now let's start with the basic netstrings. They consist of a byte count, +;; followed a colon and the binary data and a trailing comma. Examples: +;; +;; 13:Hello, World!, +;; 10:Guten Tag!, +;; 0:, +;; +;; The initial byte count allows to efficiently allocate a sufficiently +;; sized message buffer. The trailing comma serves as a hint to detect +;; incorrect netstrings. +;; +;; ## Low-level reading +;; +;; We will need some low-level reading helpers to read the bytes from +;; the input stream. These are `read-byte` as well as `read-bytes`. They +;; are split out, because doing such a simple task as reading a byte is +;; mild catastrophe in Java. So it would add some clutter to the algorithm +;; `read-netstring`. +;; +;; On the other hand they might be also useful elsewhere. +;; +;; To remove some magic numbers from the code below. + +(set! *warn-on-reflection* true) + +(def #^{:const true} i 105) +(def #^{:const true} l 108) +(def #^{:const true} d 100) +(def #^{:const true} comma 44) +(def #^{:const true} minus 45) + +;; These two are only used boxed. So we keep them extra here. + +(def e 101) +(def colon 58) + +(defn #^{:private true} read-byte + #^long [#^InputStream input] + (let [c (.read input)] + (when (neg? c) + (throw (EOFException. "Invalid netstring. Unexpected end of input."))) + ;; Here we have a quirk for example. `.read` returns -1 on end of + ;; input. However the Java `Byte` has only a range from -128 to 127. + ;; How does the fit together? + ;; + ;; The whole thing is shifted. `.read` actually returns an int + ;; between zero and 255. Everything below the value 128 stands + ;; for itself. But larger values are actually negative byte values. + ;; + ;; So we have to do some translation here. `Byte/byteValue` would + ;; do that for us, but we want to avoid boxing here. + (if (< 127 c) (- c 256) c))) + +(defn #^{:private true :tag "[B"} read-bytes + #^Object [#^InputStream input n] + (let [content (byte-array n)] + (loop [offset (int 0) + len (int n)] + (let [result (.read input content offset len)] + (when (neg? result) + (throw + (EOFException. + "Invalid netstring. Less data available than expected."))) + (when (not= result len) + (recur (+ offset result) (- len result))))) + content)) + +;; `read-long` is used for reading integers from the stream as well +;; as the byte count prefixes of byte strings. The delimiter is \: +;; for byte count prefixes and \e for integers. + +(defn #^{:private true} read-long + #^long [#^InputStream input delim] + (loop [n (long 0)] + ;; We read repeatedly a byte from the input… + (let [b (read-byte input)] + ;; …and stop at the delimiter. + (cond + (= b minus) (- (read-long input delim)) + (= b delim) n + :else (recur (+ (* n (long 10)) (- (long b) (long 48)))))))) + +;; ## Reading a netstring +;; +;; Let's dive straight into reading a netstring from an `InputStream`. +;; +;; For convenience we split the function into two subfunctions. The +;; public `read-netstring` is the normal entry point, which also checks +;; for the trailing comma after reading the payload data with the +;; private `read-netstring*`. +;; +;; The reason we need the less strict `read-netstring*` is that with +;; bencode we don't have a trailing comma. So a check would not be +;; beneficial here. +;; +;; However the consumer doesn't have to care. `read-netstring` as +;; well as `read-bencode` provide the public entry points, which do +;; the right thing. Although they both may reference the `read-netstring*` +;; underneath. +;; +;; With this in mind we define the inner helper function first. + +(declare #^"[B" string>payload + #^String stringpayload` and `stringpayload + [#^String s] + (.getBytes s "UTF-8")) + +(defn #^{:private true :tag String} stringpayload (str (alength content)))) + (.write (int colon)) + (.write content))) + +(defn write-netstring + "Write the given binary data to the output stream in form of a classic + netstring." + [#^OutputStream output content] + (doto output + (write-netstring* content) + (.write (int comma)))) + +;; # Bencode +;; +;; However most of the time we don't want to send simple blobs of data +;; back and forth. The data sent between the communication peers usually +;; have some structure, which has to be carried along the way to the +;; other side. Here [bencode][bc] come into play. +;; +;; Bencode defines additionally to netstrings easily parseable structures +;; for lists, maps and numbers. It allows to communicate information +;; about the data structure to the peer on the other side. +;; +;; ## Tokens +;; +;; The data is encoded in tokens in bencode. There are several types of +;; tokens: +;; +;; * A netstring without trailing comma for string data. +;; * A tag specifiyng the type of the following tokens. +;; The tag may be one of these: +;; * `\i` to encode integers. +;; * `\l` to encode lists of items. +;; * `\d` to encode maps of item pairs. +;; * `\e` to end the a previously started tag. +;; +;; ## Reading bencode +;; +;; Reading bencode encoded data is basically parsing a stream of tokens +;; from the input. Hence we need a read-token helper which allows to +;; retrieve the next token. + +(defn #^{:private true} read-token + [#^PushbackInputStream input] + (let [ch (read-byte input)] + (cond + (= (long e) ch) nil + (= i ch) :integer + (= l ch) :list + (= d ch) :map + :else (do + (.unread input (int ch)) + (read-netstring* input))))) + +;; To read the bencode encoded data we walk a long the sequence of tokens +;; and act according to the found tags. + +(declare read-integer read-list read-map) + +(defn read-bencode + "Read bencode token from the input stream." + [input] + (let [token (read-token input)] + (case token + :integer (read-integer input) + :list (read-list input) + :map (read-map input) + token))) + +;; Of course integers and the collection types are have to treated specially. +;; +;; Integers for example consist of a sequence of decimal digits. + +(defn #^{:private true} read-integer + [input] + (read-long input e)) + +;; *Note:* integers are an ugly special case, which cannot be +;; handled with `read-token` or `read-netstring*`. +;; +;; Lists are just a sequence of other tokens. + +(declare token-seq) + +(defn #^{:private true} read-list + [input] + (vec (token-seq input))) + +;; Maps are sequences of key/value pairs. The keys are always +;; decoded into strings. The values are kept as is. + +(defn #^{:private true} read-map + [input] + (->> (token-seq input) + (into {} (comp (partition-all 2) + (map (fn [[k v]] + [(string> #(read-bencode input) + repeatedly + (take-while identity))) + +;; ## Writing bencode +;; +;; Writing bencode is similar easy as reading it. The main entry point +;; takes a string, map, sequence or integer and writes it according to +;; the rules to the given OutputStream. + +(defmulti write-bencode + "Write the given thing to the output stream. “Thing” means here a + string, map, sequence or integer. Alternatively an ByteArray may + be provided whose contents are written as a bytestring. Similar + the contents of a given InputStream are written as a byte string. + Named things (symbols or keywords) are written in the form + 'namespace/name'." + (fn [_output thing] + (cond + (bytes? thing) :bytes + (instance? InputStream thing) :input-stream + (integer? thing) :integer + (string? thing) :string + (symbol? thing) :named + (keyword? thing) :named + (map? thing) :map + (or (nil? thing) (coll? thing) (.isArray (class thing))) :list + :else (type thing)))) + +(defmethod write-bencode :default + [output x] + (throw (IllegalArgumentException. (str "Cannot write value of type " (class x))))) + +;; The following methods should be pretty straight-forward. +;; +;; The easiest case is of course when we already have a byte array. +;; We can simply pass it on to the underlying machinery. + +(defmethod write-bencode :bytes + [output bytes] + (write-netstring* output bytes)) + +;; For strings we simply write the string as a netstring without +;; trailing comma after encoding the string as UTF-8 bytes. + +(defmethod write-bencode :string + [output string] + (write-netstring* output (string>payload string))) + +;; Streaming does not really work, since we need to know the +;; number of bytes to write upfront. So we read in everything +;; for InputStreams and pass on the byte array. + +(defmethod write-bencode :input-stream + [output stream] + (let [bytes (ByteArrayOutputStream.)] + (io/copy stream bytes) + (write-netstring* output (.toByteArray bytes)))) + +;; Integers are again the ugly special case. + +(defmethod write-bencode :integer + [#^OutputStream output n] + (doto output + (.write (int i)) + (.write (string>payload (str n))) + (.write (int e)))) + +;; Symbols and keywords are converted to a string of the +;; form 'namespace/name' or just 'name' in case its not +;; qualified. We do not add colons for keywords since the +;; other side might not have the notion of keywords. + +(defmethod write-bencode :named + [output thing] + (let [nspace (namespace thing) + name (name thing)] + (->> (str (when nspace (str nspace "/")) name) + string>payload + (write-netstring* output)))) + +;; Lists as well as maps work recursively to print their elements. + +(defmethod write-bencode :list + [#^OutputStream output lst] + (.write output (int l)) + (doseq [elt lst] + (write-bencode output elt)) + (.write output (int e))) + +;; However, maps are a bit special because their keys are sorted +;; lexicographically based on their byte string represantation. + +(declare lexicographically) + +(defmethod write-bencode :map + [#^OutputStream output m] + (let [translation (into {} (map (juxt string>payload identity) (keys m))) + key-strings (sort lexicographically (keys translation)) + >value (comp m translation)] + (.write output (int d)) + (doseq [k key-strings] + (write-netstring* output k) + (write-bencode output (>value k))) + (.write output (int e)))) + +;; However, since byte arrays are not `Comparable` we need a custom +;; comparator which we can feed to `sort`. + +(defn #^{:private true} lexicographically + [#^"[B" a #^"[B" b] + (let [alen (alength a) + blen (alength b) + len (min alen blen)] + (loop [i 0] + (if (== i len) + (- alen blen) + (let [x (- (int (aget a i)) (int (aget b i)))] + (if (zero? x) + (recur (inc i)) + x)))))) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index cf2fc3e7..e5f48a4c 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -204,6 +204,8 @@ java.security.MessageDigest (instance? java.io.InputStream v) java.io.InputStream + (instance? java.io.OutputStream v) + java.io.OutputStream (instance? java.nio.file.FileSystem v) java.nio.file.FileSystem))))) diff --git a/src/babashka/impl/clojure/main.clj b/src/babashka/impl/clojure/main.clj index 3d8a9f2f..db26af93 100644 --- a/src/babashka/impl/clojure/main.clj +++ b/src/babashka/impl/clojure/main.clj @@ -48,6 +48,11 @@ *e nil] ~@body)) +(def ^{:doc "A sequence of lib specs that are applied to `require` +by default when a new command-line REPL is started."} repl-requires + '[[clojure.repl :refer (dir doc)] + [clojure.pprint :refer (pprint)]]) + (defn repl "Generic, reusable, read-eval-print loop. By default, reads from *in*, writes to *out*, and prints exception summaries to *err*. If you use the diff --git a/src/babashka/impl/clojure/stacktrace.clj b/src/babashka/impl/clojure/stacktrace.clj index 4f088b16..07f19ef1 100644 --- a/src/babashka/impl/clojure/stacktrace.clj +++ b/src/babashka/impl/clojure/stacktrace.clj @@ -1,10 +1,16 @@ (ns babashka.impl.clojure.stacktrace {:no-doc true} - (:require [clojure.stacktrace :as stacktrace])) + (:require [clojure.stacktrace :as stacktrace] + [sci.core :as sci])) + +(defmacro wrap-out [f] + `(fn [& ~'args] + (binding [*out* @sci/out] + (apply ~f ~'args)))) (def stacktrace-namespace {'root-cause stacktrace/root-cause - 'print-trace-element stacktrace/print-trace-element - 'print-throwable stacktrace/print-throwable - 'print-stack-trace stacktrace/print-stack-trace - 'print-cause-trace stacktrace/print-cause-trace}) + 'print-trace-element (wrap-out stacktrace/print-trace-element) + 'print-throwable (wrap-out stacktrace/print-throwable) + 'print-stack-trace (wrap-out stacktrace/print-stack-trace) + 'print-cause-trace (wrap-out stacktrace/print-cause-trace)}) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj new file mode 100644 index 00000000..ce8a6309 --- /dev/null +++ b/src/babashka/impl/nrepl_server.clj @@ -0,0 +1,236 @@ +(ns babashka.impl.nrepl-server + {:no-doc true} + (:refer-clojure :exclude [send future binding]) + (:require [babashka.impl.bencode.core :refer [write-bencode read-bencode]] + [clojure.string :as str] + [sci.core :as sci] + [sci.impl.interpreter :refer [eval-string*]] + [sci.impl.utils :as sci-utils] + [sci.impl.vars :as vars]) + (:import [java.io StringWriter OutputStream InputStream PushbackInputStream EOFException] + [java.net ServerSocket])) + +(set! *warn-on-reflection* true) + +(def port 1667) +(def dev? (volatile! nil)) + +(defn response-for [old-msg msg] + (let [session (get old-msg :session "none") + m (assoc msg "session" session) + id (get old-msg :id "unknown") + m (assoc m "id" id)] + m)) + +(defn send [^OutputStream os msg] + ;;(when @dev? (prn "Sending" msg)) + (write-bencode os msg) + (.flush os)) + +(defn send-exception [os msg ^Throwable ex] + (let [ex-map (Throwable->map ex) + ex-name (-> ex-map :via first :type) + cause (:cause ex-map)] + (when @dev? (prn "sending exception" ex-map)) + (send os (response-for msg {"err" (str ex-name ": " cause "\n")})) + (send os (response-for msg {"ex" (str "class " ex-name) + "root-ex" (str "class " ex-name) + "status" #{"eval-error"}})) + (send os (response-for msg {"status" #{"done"}})))) + +(defn eval-msg [ctx o msg #_threads] + (try + (let [ns-str (get msg :ns) + sci-ns (if ns-str + (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false) + (sci-utils/namespace-object (:env ctx) 'user nil false))] + (sci/binding [vars/current-ns sci-ns + sci/print-length @sci/print-length] + (let [session (get msg :session "none") + id (get msg :id "unknown")] + (when @dev? (println "Registering thread for" (str session "-" id))) + ;; (swap! threads assoc [session id] (Thread/currentThread)) + (let [code-str (get msg :code) + sw (StringWriter.) + value (if (str/blank? code-str) + ::nil + (sci/binding [sci/out sw + vars/current-ns @vars/current-ns] (eval-string* ctx code-str))) + out-str (not-empty (str sw)) + env (:env ctx)] + (swap! env update-in [:namespaces 'clojure.core] + (fn [core] + (assoc core + '*1 value + '*2 (get core '*1) + '*3 (get core '*2)))) + (when @dev? (println "out str:" out-str)) + (when out-str + (send o (response-for msg {"out" out-str}))) + (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} + (not (identical? value ::nil)) (assoc "value" (pr-str value))))) + (send o (response-for msg {"status" #{"done"}})))))) + (catch Exception ex + (swap! (:env ctx) update-in [:namespaces 'clojure.core] + (fn [core] + (assoc core '*e ex))) + (send-exception o msg ex)))) + +(defn fully-qualified-syms [ctx ns-sym] + (let [syms (eval-string* ctx (format "(keys (ns-map '%s))" ns-sym)) + sym-strs (map #(str "`" %) syms) + sym-expr (str "[" (str/join " " sym-strs) "]") + syms (eval-string* ctx sym-expr)] + syms)) + +(defn match [_alias->ns ns->alias query [sym-ns sym-name qualifier]] + (let [pat (re-pattern query)] + (or (when (and (identical? :unqualified qualifier) (re-find pat sym-name)) + [sym-ns sym-name]) + (when sym-ns + (or (when (re-find pat (str sym-ns "/" sym-name)) + [sym-ns (str sym-ns "/" sym-name)]) + (when (re-find pat (str (get ns->alias (symbol sym-ns)) "/" sym-name)) + [sym-ns (str (get ns->alias (symbol sym-ns)) "/" sym-name)])))))) + +(defn complete [ctx o msg] + (try + (let [ns-str (get msg :ns) + sci-ns (if ns-str + (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false) + (sci-utils/namespace-object (:env ctx) 'user nil false))] + (sci/binding [vars/current-ns sci-ns] + (let [ + ;;ns-sym (symbol ns) + query (:symbol msg) + from-current-ns (fully-qualified-syms ctx (eval-string* ctx "(ns-name *ns*)")) + from-current-ns (map (fn [sym] + [(namespace sym) (name sym) :unqualified]) + from-current-ns) + alias->ns (eval-string* ctx "(let [m (ns-aliases *ns*)] (zipmap (keys m) (map ns-name (vals m))))") + ns->alias (zipmap (vals alias->ns) (keys alias->ns)) + from-aliased-nss (doall (mapcat + (fn [alias] + (let [ns (get alias->ns alias) + syms (eval-string* ctx (format "(keys (ns-publics '%s))" ns))] + (map (fn [sym] + [(str ns) (str sym) :qualified]) + syms))) + (keys alias->ns))) + svs (concat from-current-ns from-aliased-nss) + completions (keep (fn [entry] + (match alias->ns ns->alias query entry)) + svs) + completions (mapv (fn [[namespace name]] + {"candidate" (str name) "ns" (str namespace) #_"type" #_"function"}) + completions)] + (when @dev? (prn "completions" completions)) + (send o (response-for msg {"completions" completions + "status" #{"done"}}))))) + (catch Throwable e + (println e) + (send o (response-for msg {"completions" [] + "status" #{"done"}}))))) + +;; GraalVM doesn't support the .stop method on Threads, so for now we will have to live without interrupt +#_(defn interrupt [_ctx os msg threads] + (let [session (get msg :session "none") + id (get msg :interrupt-id)] + (when-let [t (get @threads [session id])] + (when @dev? (println "Killing thread" (str session "-" id))) + (try (.stop ^java.lang.Thread t) + (catch Throwable e + (println e)))) + (send os (response-for msg {"status" #{"done"}})))) + +(defn read-msg [msg] + (-> (zipmap (map keyword (keys msg)) + (map #(if (bytes? %) + (String. (bytes %)) + %) (vals msg))) + (update :op keyword))) + +(defn session-loop [ctx ^InputStream is os id #_threads] + (when @dev? (println "Reading!" id (.available is))) + (when-let [msg (try (read-bencode is) + (catch EOFException _ + (println "Client closed connection.")))] + (let [msg (read-msg msg)] + (when @dev? (prn "Received" msg)) + (case (get msg :op) + :clone (do + (when @dev? (println "Cloning!")) + (let [id (str (java.util.UUID/randomUUID))] + (send os (response-for msg {"new-session" id "status" #{"done"}})) + (recur ctx is os id #_threads))) + :eval (do + (eval-msg ctx os msg #_threads) + (recur ctx is os id #_threads)) + :load-file (let [file (:file msg) + msg (assoc msg :code file)] + (eval-msg ctx os msg #_threads) + (recur ctx is os id #_threads)) + :complete (do + (complete ctx os msg) + (recur ctx is os id #_threads)) + ;; :interrupt (do + ;; (interrupt ctx os msg threads) + ;; (recur ctx is os id threads)) + :describe + (do (send os (response-for msg {"status" #{"done"} + "aux" {} + "ops" (zipmap #{"clone", "describe", "eval"} + (repeat {})) + "versions" {} #_{"nrepl" {"major" "0" + "minor" "4" + "incremental" "0" + "qualifier" ""} + "clojure" + {"*clojure-version*" + (zipmap (map name (keys *clojure-version*)) + (vals *clojure-version*))}}})) + (recur ctx is os id #_threads)) + ;; fallback + (do (when @dev? + (println "Unhandled message" msg)) + (send os (response-for msg {"status" #{"error" "unknown-op" "done"}})) + (recur ctx is os id #_threads)))))) + +(defn listen [ctx ^ServerSocket listener] + (when @dev? (println "Listening")) + (let [client-socket (.accept listener) + in (.getInputStream client-socket) + in (PushbackInputStream. in) + out (.getOutputStream client-socket) + #_threads #_(atom {})] + (when @dev? (println "Connected.")) + (sci/future + (sci/binding + ;; allow *ns* to be set! inside future + [vars/current-ns (vars/->SciNamespace 'user nil) + sci/print-length @sci/print-length] + (session-loop ctx in out "pre-init" #_threads))) + (recur ctx listener))) + + +(def server (atom nil)) + +(defn stop-server! [] + (when-let [s @server] + (.close ^ServerSocket s) + (reset! server nil))) + +(defn start-server! [ctx host+port] + (vreset! dev? (= "true" (System/getenv "BABASHKA_DEV"))) + (let [parts (str/split host+port #":") + [address port] (if (= 1 (count parts)) + [nil (Integer. ^String (first parts))] + [(java.net.InetAddress/getByName (first parts)) + (Integer. ^String (second parts))]) + host+port (if-not address (str "localhost:" port) + host+port)] + #_(complete ctx nil {:symbol "json"}) + (println "Starting nREPL server at" host+port) + (let [socket-server (new ServerSocket port 0 address)] + (reset! server socket-server) + (listen ctx socket-server)))) diff --git a/src/babashka/impl/transit.clj b/src/babashka/impl/transit.clj index e7c84311..73eb7026 100644 --- a/src/babashka/impl/transit.clj +++ b/src/babashka/impl/transit.clj @@ -3,6 +3,7 @@ [sci.impl.namespaces :refer [copy-var]] [sci.impl.vars :as vars])) + (def tns (vars/->SciNamespace 'cognitect.transit nil)) (def transit-namespace diff --git a/src/babashka/main.clj b/src/babashka/main.clj index d77d5297..e1f7c80b 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -2,18 +2,20 @@ {:no-doc true} (:require [babashka.impl.async :refer [async-namespace async-protocols-namespace]] + [babashka.impl.bencode :refer [bencode-namespace]] [babashka.impl.cheshire :refer [cheshire-core-namespace]] [babashka.impl.classes :as classes] [babashka.impl.classpath :as cp] [babashka.impl.clojure.core :refer [core-extras]] [babashka.impl.clojure.java.io :refer [io-namespace]] [babashka.impl.clojure.java.shell :refer [shell-namespace]] - [babashka.impl.clojure.main :refer [demunge]] + [babashka.impl.clojure.main :as clojure-main :refer [demunge]] [babashka.impl.clojure.pprint :refer [pprint-namespace]] [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace]] [babashka.impl.common :as common] [babashka.impl.csv :as csv] [babashka.impl.curl :refer [curl-namespace]] + [babashka.impl.nrepl-server :as nrepl-server] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] [babashka.impl.repl :as repl] [babashka.impl.socket-repl :as socket-repl] @@ -115,6 +117,12 @@ (assoc opts-map :socket-repl (or (first options) "1666")))) + ("--nrepl-server") + (let [options (next options)] + (recur (next options) + (assoc opts-map + :nrepl (or (first options) + "1667")))) ("--eval", "-e") (let [options (next options)] (recur (next options) @@ -158,7 +166,7 @@ (def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] [ ( --classpath | -cp ) ] [ --uberscript ] [ ( --main | -m ) | -e | -f | - --repl | --socket-repl [:] ] + --repl | --socket-repl [:] | --nrepl-server [:] ] [ arg* ]") (defn print-usage [] (println usage-string)) @@ -188,6 +196,7 @@ -m, --main Call the -main function from namespace with args. --repl Start REPL. Use rlwrap for history. --socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666). + --nrepl-server Start nREPL server. Specify port (e.g. 1667) or host and port separated by colon (e.g. 127.0.0.1:1667). --time Print execution time before exiting. -- Stop parsing args and pass everything after -- to *command-line-args* @@ -218,6 +227,11 @@ Everything after that is bound to *command-line-args*.")) ;; hang until SIGINT @(promise)) +(defn start-nrepl! [address ctx] + (nrepl-server/start-server! ctx address) + ;; hang until SIGINT + #_@(promise)) + (defn exit [n] (throw (ex-info "" {:bb/exit-code n}))) @@ -232,7 +246,8 @@ Everything after that is bound to *command-line-args*.")) csv clojure.data.csv json cheshire.core curl babashka.curl - transit cognitect.transit}) + transit cognitect.transit + bencode bencode.core}) (def cp-state (atom nil)) @@ -258,13 +273,15 @@ Everything after that is bound to *command-line-args*.")) 'clojure.data.csv csv/csv-namespace 'cheshire.core cheshire-core-namespace 'clojure.stacktrace stacktrace-namespace - 'clojure.main {'demunge demunge} + 'clojure.main {'demunge demunge + 'repl-requires clojure-main/repl-requires} 'clojure.repl {'demunge demunge} 'clojure.test t/clojure-test-namespace 'babashka.classpath {'add-classpath add-classpath*} 'clojure.pprint pprint-namespace 'babashka.curl curl-namespace - 'cognitect.transit transit-namespace}) + 'cognitect.transit transit-namespace + 'bencode.core bencode-namespace}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control @@ -295,7 +312,7 @@ Everything after that is bound to *command-line-args*.")) {:keys [:version :shell-in :edn-in :shell-out :edn-out :help? :file :command-line-args :expressions :stream? :time? - :repl :socket-repl + :repl :socket-repl :nrepl :verbose? :classpath :main :uberscript] :as _opts} (parse-opts args) @@ -403,6 +420,7 @@ Everything after that is bound to *command-line-args*.")) [(print-help) 0] repl [(repl/start-repl! sci-ctx) 0] socket-repl [(start-socket-repl! socket-repl sci-ctx) 0] + nrepl [(start-nrepl! nrepl sci-ctx) 0] (not (str/blank? expression)) (try (loop [] @@ -446,7 +464,8 @@ Everything after that is bound to *command-line-args*.")) (defn -main [& args] (if-let [dev-opts (System/getenv "BABASHKA_DEV")] - (let [{:keys [:n]} (edn/read-string dev-opts) + (let [{:keys [:n]} (if (= "true" dev-opts) {:n 1} + (edn/read-string dev-opts)) last-iteration (dec n)] (dotimes [i n] (if (< i last-iteration) diff --git a/src/babashka/wait.clj b/src/babashka/wait.clj index af2cc9d4..f4bf6999 100644 --- a/src/babashka/wait.clj +++ b/src/babashka/wait.clj @@ -17,8 +17,8 @@ opts) t0 (System/currentTimeMillis)] (loop [] - (let [v (try (with-open [_ (Socket. host port)] - (- (System/currentTimeMillis) t0)) + (let [v (try (.close (Socket. host port)) + (- (System/currentTimeMillis) t0) (catch ConnectException _e (let [took (- (System/currentTimeMillis) t0)] (if (and timeout (>= took timeout)) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj new file mode 100644 index 00000000..bec00443 --- /dev/null +++ b/test/babashka/impl/nrepl_server_test.clj @@ -0,0 +1,120 @@ +(ns babashka.impl.nrepl-server-test + (:require + [babashka.impl.bencode.core :as bencode] + [babashka.impl.nrepl-server :refer [start-server! stop-server!]] + [babashka.test-utils :as tu] + [babashka.wait :as wait] + [cheshire.core :as cheshire] + [clojure.java.shell :refer [sh]] + [clojure.test :as t :refer [deftest is testing]] + [sci.impl.opts :refer [init]]) + (:import [java.lang ProcessBuilder$Redirect])) + +(set! *warn-on-reflection* true) + +(defn bytes->str [x] + (if (bytes? x) (String. (bytes x)) + (str x))) + +(defn read-msg [msg] + (let [res (zipmap (map keyword (keys msg)) + (map #(if (bytes? %) + (String. (bytes %)) + %) + (vals msg))) + res (if-let [status (:status res)] + (assoc res :status (mapv bytes->str status)) + res)] + res)) + +(defn read-reply [in session id] + (loop [] + (let [msg (read-msg (bencode/read-bencode in))] + (if (and (= (:session msg) session) + (= (:id msg) id)) + msg + (recur))))) + +(defn nrepl-test [] + (with-open [socket (java.net.Socket. "127.0.0.1" 1667) + in (.getInputStream socket) + in (java.io.PushbackInputStream. in) + os (.getOutputStream socket)] + (bencode/write-bencode os {"op" "clone"}) + (let [session (:new-session (read-msg (bencode/read-bencode in)))] + (testing "session" + (is session)) + (testing "eval" + (bencode/write-bencode os {"op" "eval" "code" "(+ 1 2 3)" "session" session "id" 1}) + (let [msg (read-reply in session 1) + id (:id msg) + value (:value msg)] + (is (= 1 id)) + (is (= value "6")))) + (testing "load-file" + (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" 2}) + (read-reply in session 2) + (bencode/write-bencode os {"op" "eval" "code" "(foo)" "ns" "foo" "session" session "id" 3}) + (is (= ":foo" (:value (read-reply in session 3))))) + (testing "complete" + (testing "completions for fo" + (bencode/write-bencode os {"op" "complete" + "symbol" "fo" + "session" session + "id" 4 + "ns" "foo"}) + (let [reply (read-reply in session 4) + completions (:completions reply) + completions (mapv read-msg completions) + completions (into #{} (map (juxt :ns :candidate)) completions)] + (is (contains? completions ["foo" "foo"])) + (is (contains? completions ["clojure.core" "format"])))) + (testing "completions for quux should be empty" + (bencode/write-bencode os {"op" "complete" + "symbol" "quux" + "session" session "id" 6 + "ns" "foo"}) + (let [reply (read-reply in session 6) + completions (:completions reply)] + (is (empty? completions))) + (testing "unless quux is an alias" + (bencode/write-bencode os {"op" "eval" "code" "(require '[cheshire.core :as quux])" "session" session "id" 7}) + (bencode/write-bencode os {"op" "complete" "symbol" "quux" "session" session "id" 8}) + (let [reply (read-reply in session 8) + completions (:completions reply) + completions (mapv read-msg completions) + completions (into #{} (map (juxt :ns :candidate)) completions)] + (is (contains? completions ["cheshire.core" "quux/generate-string"])))))) + #_(testing "interrupt" ;; .stop doesn't work on Thread in GraalVM, this is why we can't have this yet + (bencode/write-bencode os {"op" "eval" "code" "(range)" "session" session "id" 9}) + (Thread/sleep 1000) + (bencode/write-bencode os {"op" "interrupt" "session" session "interrupt-id" 9 "id" 10}) + (is (contains? (set (:status (read-reply in session 10))) "done")))))) + +(deftest nrepl-server-test + (let [proc-state (atom nil)] + (try + (if tu/jvm? + (future + (start-server! + (init {:namespaces {'cheshire.core {'generate-string cheshire/generate-string}} + :features #{:bb}}) "0.0.0.0:1667")) + (let [pb (ProcessBuilder. ["./bb" "--nrepl-server" "0.0.0.0:1667"]) + _ (.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" 1667) + (nrepl-test) + (finally + (if tu/jvm? + (stop-server!) + (when-let [proc @proc-state] + (.destroy ^Process proc))))))) + +;;;; Scratch + +(comment + ) diff --git a/test/babashka/impl/socket_repl_test.clj b/test/babashka/impl/socket_repl_test.clj index 8bad7823..18abb4e4 100644 --- a/test/babashka/impl/socket_repl_test.clj +++ b/test/babashka/impl/socket_repl_test.clj @@ -2,10 +2,10 @@ (:require [babashka.impl.socket-repl :refer [start-repl! stop-repl!]] [babashka.test-utils :as tu] + [clojure.java.io :as io] [clojure.java.shell :refer [sh]] [clojure.string :as str] [clojure.test :as t :refer [deftest is testing]] - [clojure.java.io :as io] [sci.impl.opts :refer [init]])) (set! *warn-on-reflection* true) From 77e4ef6dd6a0118e2679e7bd9510931fc5728504 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 12:23:29 +0200 Subject: [PATCH 144/264] Update babashka.curl: always return map with :status, :headers and :body --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 57daab01..48287b00 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 57daab013d4108c5898a3a92fc00395a1e9da5ed +Subproject commit 48287b007ea6e53280413dd70351a887210e3cf2 From 58de38c073c3f0a8e4c3a4d716d8261c03ccf359 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 12:25:27 +0200 Subject: [PATCH 145/264] Document breaking change in babashka.curl --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index fff6f671..5c230d19 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,11 @@ ## Breaking changes +## v0.0.79 +- [babashka.curl#9](https://github.com/borkdude/babashka.curl/issues/9): + BREAKING! Functions in `babashka.curl` like `get`, `post`, etc. now always + return a map with `:status`, `:body`, and `:headers`. + ## v0.0.71 - #267 Change behavior of reader conditionals: the `:clj` branch is taken when it occurs before a `:bb` branch. From 62014c0e7479f3ccb115f5bb179e8827d62951aa Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 12:39:07 +0200 Subject: [PATCH 146/264] Fix babashka.curl test --- script/lib_tests/babashka_curl_test | 18 +++++++++--------- src/babashka/impl/classes.clj | 1 + src/babashka/impl/curl.clj | 20 ++++++++++++-------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/script/lib_tests/babashka_curl_test b/script/lib_tests/babashka_curl_test index 7620200e..3605234f 100755 --- a/script/lib_tests/babashka_curl_test +++ b/script/lib_tests/babashka_curl_test @@ -11,23 +11,23 @@ else fi $BB_CMD -e " -(require '[babashka.curl :as curl]) +(require '[babashka.curl :as curl] :reload-all) -(prn (subs (curl/get \"https://www.clojure.org\") 0 10)) +(prn (:status (curl/get \"https://www.clojure.org\"))) -(prn (subs (curl/get \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\") 0 10)) +(prn (:status (curl/get \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\"))) -(prn (subs (curl/post \"https://postman-echo.com/post\") 0 10)) +(prn (:status (curl/post \"https://postman-echo.com/post\"))) -(prn (subs (curl/post \"https://postman-echo.com/post\" - {:body (json/generate-string {:a 1}) +(prn (:status (curl/post \"https://postman-echo.com/post\" + {:body (json/generate-string {:a 1}) :headers {\"X-Hasura-Role\" \"admin\"} :content-type :json - :accept :json}) 0 10)) + :accept :json}))) -(prn (subs (curl/put \"https://postman-echo.com/put\" +(prn (:status (curl/put \"https://postman-echo.com/put\" {:body (json/generate-string {:a 1}) :headers {\"X-Hasura-Role\" \"admin\"} :content-type :json - :accept :json}) 0 10)) + :accept :json}))) " diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index e5f48a4c..29fbc403 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -23,6 +23,7 @@ java.io.IOException java.io.OutputStream java.io.FileReader + java.io.PushbackInputStream java.io.Reader java.io.StringReader java.io.StringWriter diff --git a/src/babashka/impl/curl.clj b/src/babashka/impl/curl.clj index fa036ff7..cf24bc60 100644 --- a/src/babashka/impl/curl.clj +++ b/src/babashka/impl/curl.clj @@ -1,12 +1,16 @@ (ns babashka.impl.curl {:no-doc true} - (:require [babashka.curl :as curl])) + (:require [babashka.curl :as curl] + [sci.impl.namespaces :refer [copy-var]] + [sci.impl.vars :as vars])) + +(def tns (vars/->SciNamespace 'babashka.curl nil)) (def curl-namespace - {'request curl/request - 'get curl/get - 'patch curl/patch - 'post curl/post - 'put curl/put - 'head curl/head - 'curl-command curl/curl-command}) + {'request (copy-var curl/request tns) + 'get (copy-var curl/get tns) + 'patch (copy-var curl/patch tns) + 'post (copy-var curl/post tns) + 'put (copy-var curl/put tns) + 'head (copy-var curl/head tns) + 'curl-command (copy-var curl/curl-command tns)}) From 3bf27445f34b7ee1fba1198696aaa2236e61d443 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 14:26:02 +0200 Subject: [PATCH 147/264] [#328] completions for clojure.test do not work --- src/babashka/impl/nrepl_server.clj | 8 ++--- test/babashka/impl/nrepl_server_test.clj | 46 +++++++++++++++--------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index ce8a6309..7d44ca36 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -88,10 +88,10 @@ (or (when (and (identical? :unqualified qualifier) (re-find pat sym-name)) [sym-ns sym-name]) (when sym-ns - (or (when (re-find pat (str sym-ns "/" sym-name)) - [sym-ns (str sym-ns "/" sym-name)]) - (when (re-find pat (str (get ns->alias (symbol sym-ns)) "/" sym-name)) - [sym-ns (str (get ns->alias (symbol sym-ns)) "/" sym-name)])))))) + (or (when (re-find pat (str (get ns->alias (symbol sym-ns)) "/" sym-name)) + [sym-ns (str (get ns->alias (symbol sym-ns)) "/" sym-name)]) + (when (re-find pat (str sym-ns "/" sym-name)) + [sym-ns (str sym-ns "/" sym-name)])))))) (defn complete [ctx o msg] (try diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index bec00443..84c81b54 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -2,10 +2,10 @@ (:require [babashka.impl.bencode.core :as bencode] [babashka.impl.nrepl-server :refer [start-server! stop-server!]] + [babashka.main :as main] [babashka.test-utils :as tu] [babashka.wait :as wait] [cheshire.core :as cheshire] - [clojure.java.shell :refer [sh]] [clojure.test :as t :refer [deftest is testing]] [sci.impl.opts :refer [init]]) (:import [java.lang ProcessBuilder$Redirect])) @@ -41,29 +41,31 @@ in (java.io.PushbackInputStream. in) os (.getOutputStream socket)] (bencode/write-bencode os {"op" "clone"}) - (let [session (:new-session (read-msg (bencode/read-bencode in)))] + (let [session (:new-session (read-msg (bencode/read-bencode in))) + id (atom 0) + new-id! #(swap! id inc)] (testing "session" (is session)) (testing "eval" - (bencode/write-bencode os {"op" "eval" "code" "(+ 1 2 3)" "session" session "id" 1}) - (let [msg (read-reply in session 1) + (bencode/write-bencode os {"op" "eval" "code" "(+ 1 2 3)" "session" session "id" (new-id!)}) + (let [msg (read-reply in session @id) id (:id msg) value (:value msg)] (is (= 1 id)) (is (= value "6")))) (testing "load-file" - (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" 2}) - (read-reply in session 2) - (bencode/write-bencode os {"op" "eval" "code" "(foo)" "ns" "foo" "session" session "id" 3}) - (is (= ":foo" (:value (read-reply in session 3))))) + (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" (new-id!)}) + (read-reply in session @id) + (bencode/write-bencode os {"op" "eval" "code" "(foo)" "ns" "foo" "session" session "id" (new-id!)}) + (is (= ":foo" (:value (read-reply in session @id))))) (testing "complete" (testing "completions for fo" (bencode/write-bencode os {"op" "complete" "symbol" "fo" "session" session - "id" 4 + "id" (new-id!) "ns" "foo"}) - (let [reply (read-reply in session 4) + (let [reply (read-reply in session @id) completions (:completions reply) completions (mapv read-msg completions) completions (into #{} (map (juxt :ns :candidate)) completions)] @@ -72,19 +74,29 @@ (testing "completions for quux should be empty" (bencode/write-bencode os {"op" "complete" "symbol" "quux" - "session" session "id" 6 + "session" session "id" (new-id!) "ns" "foo"}) - (let [reply (read-reply in session 6) + (let [reply (read-reply in session @id) completions (:completions reply)] (is (empty? completions))) (testing "unless quux is an alias" - (bencode/write-bencode os {"op" "eval" "code" "(require '[cheshire.core :as quux])" "session" session "id" 7}) - (bencode/write-bencode os {"op" "complete" "symbol" "quux" "session" session "id" 8}) - (let [reply (read-reply in session 8) + (bencode/write-bencode os {"op" "eval" "code" "(require '[cheshire.core :as quux])" "session" session "id" (new-id!)}) + (read-reply in session @id) + (bencode/write-bencode os {"op" "complete" "symbol" "quux" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) completions (:completions reply) completions (mapv read-msg completions) completions (into #{} (map (juxt :ns :candidate)) completions)] - (is (contains? completions ["cheshire.core" "quux/generate-string"])))))) + (is (contains? completions ["cheshire.core" "quux/generate-string"]))))) + (testing "completions for clojure.test" + (bencode/write-bencode os {"op" "eval" "code" "(require '[clojure.test :as test])" "session" session "id" (new-id!)}) + (read-reply in session @id) + (bencode/write-bencode os {"op" "complete" "symbol" "test" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) + completions (:completions reply) + completions (mapv read-msg completions) + completions (into #{} (map (juxt :ns :candidate)) completions)] + (is (contains? completions ["clojure.test" "test/deftest"]))))) #_(testing "interrupt" ;; .stop doesn't work on Thread in GraalVM, this is why we can't have this yet (bencode/write-bencode os {"op" "eval" "code" "(range)" "session" session "id" 9}) (Thread/sleep 1000) @@ -97,7 +109,7 @@ (if tu/jvm? (future (start-server! - (init {:namespaces {'cheshire.core {'generate-string cheshire/generate-string}} + (init {:namespaces main/namespaces :features #{:bb}}) "0.0.0.0:1667")) (let [pb (ProcessBuilder. ["./bb" "--nrepl-server" "0.0.0.0:1667"]) _ (.redirectError pb ProcessBuilder$Redirect/INHERIT) From c738398eea17af736d220c6104a2cf84f1ce56d0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 15:08:42 +0200 Subject: [PATCH 148/264] Add java.lang.Byte, test bencode from source --- README.md | 1 + script/lib_tests/bencode_test | 18 ++++++++++++++++++ script/run_lib_tests | 1 + src/babashka/impl/classes.clj | 1 + src/babashka/main.clj | 1 + 5 files changed, 22 insertions(+) create mode 100755 script/lib_tests/bencode_test diff --git a/README.md b/README.md index d366c9ab..87726412 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ enumerated explicitly. - [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv` - [`cheshire.core`](https://github.com/dakrone/cheshire) aliased as `json` - [`cognitect.transit`](https://github.com/cognitect/transit-clj) aliased as `transit` +- [`bencode.core`](https://github.com/nrepl/bencode) aliased as `bencode`: `read-bencode`, `write-bencode`. A selection of java classes are available, see `babashka/impl/classes.clj`. diff --git a/script/lib_tests/bencode_test b/script/lib_tests/bencode_test new file mode 100755 index 00000000..1fc96a12 --- /dev/null +++ b/script/lib_tests/bencode_test @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -eou pipefail + +export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {borkdude/bencode {:git/url "https://github.com/borkdude/bencode" :sha "fc2bd007fee318cb04fdb9e0844e69d42cacaf36" :deps/manifest :deps}}}' -Spath) + +ENV=${BABASHKA_TEST_ENV:-} + +if [ "$ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + +$BB_CMD -e " +(require '[bencode.core :as bencode] :reload-all) +(with-open [os (java.io.ByteArrayOutputStream.)] (bencode/write-bencode os {\"greeting\" \"Good morning\"}) (str os)) +" diff --git a/script/run_lib_tests b/script/run_lib_tests index aaa56bf3..720a5438 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -11,3 +11,4 @@ script/lib_tests/medley_test script/lib_tests/babashka_curl_test script/lib_tests/cprop_test script/lib_tests/comb_test +script/lib_tests/bencode_test diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 29fbc403..fc500fe1 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -31,6 +31,7 @@ java.lang.ArithmeticException java.lang.AssertionError java.lang.Boolean + java.lang.Byte java.lang.Class java.lang.Double java.lang.Exception diff --git a/src/babashka/main.clj b/src/babashka/main.clj index e1f7c80b..e893bd52 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -357,6 +357,7 @@ Everything after that is bound to *command-line-args*.")) :imports '{ArithmeticException java.lang.ArithmeticException AssertionError java.lang.AssertionError Boolean java.lang.Boolean + Byte java.lang.Byte Class java.lang.Class Double java.lang.Double Exception java.lang.Exception From 322d3e123b5ca0b2ac832d41ca28d864f446e925 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 15:42:54 +0200 Subject: [PATCH 149/264] Don't run bencode from source --- script/lib_tests/bencode_test | 18 ------------------ script/run_lib_tests | 1 - 2 files changed, 19 deletions(-) delete mode 100755 script/lib_tests/bencode_test diff --git a/script/lib_tests/bencode_test b/script/lib_tests/bencode_test deleted file mode 100755 index 1fc96a12..00000000 --- a/script/lib_tests/bencode_test +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -eou pipefail - -export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {borkdude/bencode {:git/url "https://github.com/borkdude/bencode" :sha "fc2bd007fee318cb04fdb9e0844e69d42cacaf36" :deps/manifest :deps}}}' -Spath) - -ENV=${BABASHKA_TEST_ENV:-} - -if [ "$ENV" = "native" ]; then - BB_CMD="./bb" -else - BB_CMD="lein bb" -fi - -$BB_CMD -e " -(require '[bencode.core :as bencode] :reload-all) -(with-open [os (java.io.ByteArrayOutputStream.)] (bencode/write-bencode os {\"greeting\" \"Good morning\"}) (str os)) -" diff --git a/script/run_lib_tests b/script/run_lib_tests index 720a5438..aaa56bf3 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -11,4 +11,3 @@ script/lib_tests/medley_test script/lib_tests/babashka_curl_test script/lib_tests/cprop_test script/lib_tests/comb_test -script/lib_tests/bencode_test From 86e4e1e893e5ae9a6c38c11e3e2cc1655e7f5b07 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 16:12:34 +0200 Subject: [PATCH 150/264] v0.0.79 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 75afeb80..d39e547e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.79-SNAPSHOT \ No newline at end of file +0.0.79 \ No newline at end of file From 648ca2479faca4129e2d068b16dad02c1ff3685a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 16:34:57 +0200 Subject: [PATCH 151/264] minor --- script/reflection.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/script/reflection.clj b/script/reflection.clj index 56a1f21a..315872c0 100755 --- a/script/reflection.clj +++ b/script/reflection.clj @@ -1,6 +1,9 @@ #!/usr/bin/env bb -(require '[clojure.java.io :as io] '[clojure.string :as str] '[clojure.java.shell :refer [sh]]) +(require '[clojure.java.io :as io] + '[clojure.java.shell :refer [sh]] + '[clojure.string :as str]) + (def version (str/trim (slurp (io/file "resources" "BABASHKA_VERSION")))) (sh "lein" "with-profiles" "+reflection" "run") (io/copy (io/file "reflection.json") (io/file (str "babashka-" version "-reflection.json"))) From 250dbea296ad3aa83b90c658220b2c2a51544cc1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Apr 2020 16:38:17 +0200 Subject: [PATCH 152/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 009d3772..d39e547e 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.78 \ No newline at end of file +0.0.79 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d39e547e..6d03ff2c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.79 \ No newline at end of file +0.0.80-SNAPSHOT \ No newline at end of file From abd5ca93f84520042594ad0b4311babcbe13086e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 10:03:17 +0200 Subject: [PATCH 153/264] README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 87726412..dd9d6efe 100644 --- a/README.md +++ b/README.md @@ -1166,6 +1166,7 @@ example. If you get prompted with a login, use `admin`/`admin`. ## Thanks - [adgoji](https://www.adgoji.com/) for financial support +- [CircleCI](https://circleci.com/) for providing free access to their 8GB memory tier - [Nikita Prokopov](https://github.com/tonsky) for the logo - [contributors](https://github.com/borkdude/babashka/graphs/contributors) and other users posting issues with bug reports and ideas From 9b2bb96276c2d720701b8cc43df37a36a98aa632 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 11:32:20 +0200 Subject: [PATCH 154/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd9d6efe..5f178e36 100644 --- a/README.md +++ b/README.md @@ -1166,7 +1166,7 @@ example. If you get prompted with a login, use `admin`/`admin`. ## Thanks - [adgoji](https://www.adgoji.com/) for financial support -- [CircleCI](https://circleci.com/) for providing free access to their 8GB memory tier +- [CircleCI](https://circleci.com/) for CI and additional support - [Nikita Prokopov](https://github.com/tonsky) for the logo - [contributors](https://github.com/borkdude/babashka/graphs/contributors) and other users posting issues with bug reports and ideas From 3242e0dab3a3df9de276018e3e2b8b4485047f5e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 11:46:55 +0200 Subject: [PATCH 155/264] README: bencode --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 5f178e36..7790b655 100644 --- a/README.md +++ b/README.md @@ -710,6 +710,26 @@ This can be useful for talking to Docker: :RepoTags) ;;=> ["borkdude/babashka:latest"] ``` +## Bencode + +Babashka comes with the [nrepl/bencode](https://github.com/nrepl/bencode) +library which allows you to read and write bencode messages to a socket. A +simple example which gets the Clojure version from an nREPL server started with +`lein repl`: + +``` clojure +(ns nrepl-client + (:require [bencode.core :as b])) + +(let [s (java.net.Socket. "localhost" 65274) + out (.getOutputStream s) + in (java.io.PushbackInputStream. (.getInputStream s)) + _ (b/write-bencode out {"op" "describe"}) + clojure-version (get-in (b/read-bencode in) ["versions" "clojure" "version-string"])] + (String. clojure-version "UTF-8")) ;;=> "1.10.0" +``` + + ## Differences with Clojure Babashka is implemented using the [Small Clojure From 847f872df8b2d69888a5ccc6d0a791b742d3a284 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 11:54:10 +0200 Subject: [PATCH 156/264] README --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7790b655..52e58bcc 100644 --- a/README.md +++ b/README.md @@ -714,19 +714,22 @@ This can be useful for talking to Docker: Babashka comes with the [nrepl/bencode](https://github.com/nrepl/bencode) library which allows you to read and write bencode messages to a socket. A -simple example which gets the Clojure version from an nREPL server started with -`lein repl`: +simple example which evaluates a Clojure expression on an nREPL server started +with `lein repl`: ``` clojure (ns nrepl-client (:require [bencode.core :as b])) -(let [s (java.net.Socket. "localhost" 65274) - out (.getOutputStream s) - in (java.io.PushbackInputStream. (.getInputStream s)) - _ (b/write-bencode out {"op" "describe"}) - clojure-version (get-in (b/read-bencode in) ["versions" "clojure" "version-string"])] - (String. clojure-version "UTF-8")) ;;=> "1.10.0" +(defn nrepl-eval [port expr] + (let [s (java.net.Socket. "localhost" port) + out (.getOutputStream s) + in (java.io.PushbackInputStream. (.getInputStream s)) + _ (b/write-bencode out {"op" "eval" "code" (pr-str expr)}) + value (get (b/read-bencode in) "value")] + (read-string value))) + +(nrepl-eval 65274 '(+ 1 2 3)) ;;=> 6 ``` From 249fc0a5a58c7719cd5b59f38aeb461bcffef027 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 23:17:07 +0200 Subject: [PATCH 157/264] [#19] make ns key optional in nREPL messages --- src/babashka/impl/clojure/core/server.clj | 4 ++-- src/babashka/impl/nrepl_server.clj | 28 ++++++++++------------- test/babashka/impl/nrepl_server_test.clj | 18 ++++++++++++++- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/babashka/impl/clojure/core/server.clj b/src/babashka/impl/clojure/core/server.clj index 113934a0..3de2f97e 100644 --- a/src/babashka/impl/clojure/core/server.clj +++ b/src/babashka/impl/clojure/core/server.clj @@ -1,5 +1,5 @@ -;; Modified / stripped version of clojure.core.server for use with babashka on -;; GraalVM. +;; Modified / stripped version of clojure.core.server for use with babashka on +;; GraalVM. ;; ;; Copyright (c) Rich Hickey. All rights reserved. ;; The use and distribution terms for this software are covered by the diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 7d44ca36..89a46ec7 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -41,21 +41,20 @@ (defn eval-msg [ctx o msg #_threads] (try (let [ns-str (get msg :ns) - sci-ns (if ns-str - (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false) - (sci-utils/namespace-object (:env ctx) 'user nil false))] - (sci/binding [vars/current-ns sci-ns - sci/print-length @sci/print-length] + sw (StringWriter.)] + (sci/with-bindings (cond-> {sci/out sw} + ns-str + (assoc vars/current-ns + (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false))) + (when @dev? (println "current ns" (vars/current-ns-name))) (let [session (get msg :session "none") id (get msg :id "unknown")] (when @dev? (println "Registering thread for" (str session "-" id))) ;; (swap! threads assoc [session id] (Thread/currentThread)) (let [code-str (get msg :code) - sw (StringWriter.) value (if (str/blank? code-str) ::nil - (sci/binding [sci/out sw - vars/current-ns @vars/current-ns] (eval-string* ctx code-str))) + (eval-string* ctx code-str)) out-str (not-empty (str sw)) env (:env ctx)] (swap! env update-in [:namespaces 'clojure.core] @@ -96,13 +95,10 @@ (defn complete [ctx o msg] (try (let [ns-str (get msg :ns) - sci-ns (if ns-str - (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false) - (sci-utils/namespace-object (:env ctx) 'user nil false))] - (sci/binding [vars/current-ns sci-ns] - (let [ - ;;ns-sym (symbol ns) - query (:symbol msg) + sci-ns (when ns-str + (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false))] + (sci/binding [vars/current-ns (or sci-ns @vars/current-ns)] + (let [query (:symbol msg) from-current-ns (fully-qualified-syms ctx (eval-string* ctx "(ns-name *ns*)")) from-current-ns (map (fn [sym] [(namespace sym) (name sym) :unqualified]) @@ -179,7 +175,7 @@ :describe (do (send os (response-for msg {"status" #{"done"} "aux" {} - "ops" (zipmap #{"clone", "describe", "eval"} + "ops" (zipmap #{"clone" "eval" "load-file" "complete" "describe"} (repeat {})) "versions" {} #_{"nrepl" {"major" "0" "minor" "4" diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index 84c81b54..4175de2b 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -52,7 +52,23 @@ id (:id msg) value (:value msg)] (is (= 1 id)) - (is (= value "6")))) + (is (= value "6"))) + (testing "creating a namespace and evaluating something in it" + (bencode/write-bencode os {"op" "eval" + "code" "(ns ns0) (defn foo [] :foo0) (ns ns1) (defn foo [] :foo1)" + "session" session + "id" (new-id!)}) + (read-reply in session @id) + (testing "not providing the ns key evaluates in the last defined namespace" + (bencode/write-bencode os {"op" "eval" "code" "(foo)" "session" session "id" (new-id!)}) + (is (= ":foo1" (:value (read-reply in session @id))))) + (testing "explicitly providing the ns key evaluates in that namespace" + (bencode/write-bencode os {"op" "eval" + "code" "(foo)" + "session" session + "id" (new-id!) + "ns" "ns0"}) + (is (= ":foo0" (:value (read-reply in session @id))))))) (testing "load-file" (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" (new-id!)}) (read-reply in session @id) From c785a1d1f63fda6d6843c34e6f812bf9d5c70623 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 23:18:03 +0200 Subject: [PATCH 158/264] [#331] make ns key optional in nREPL messages (see prev. commit) From 2272536026c46b0790b08ef5bf6467f26520e56f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 23:31:36 +0200 Subject: [PATCH 159/264] [#329] ignore non-existing ns in nREPL message --- src/babashka/impl/nrepl_server.clj | 5 ++--- test/babashka/impl/nrepl_server_test.clj | 9 ++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 89a46ec7..2f65dfce 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -41,11 +41,10 @@ (defn eval-msg [ctx o msg #_threads] (try (let [ns-str (get msg :ns) + sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false)) sw (StringWriter.)] (sci/with-bindings (cond-> {sci/out sw} - ns-str - (assoc vars/current-ns - (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false))) + sci-ns (assoc vars/current-ns sci-ns)) (when @dev? (println "current ns" (vars/current-ns-name))) (let [session (get msg :session "none") id (get msg :id "unknown")] diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index 4175de2b..42f3bca1 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -68,7 +68,14 @@ "session" session "id" (new-id!) "ns" "ns0"}) - (is (= ":foo0" (:value (read-reply in session @id))))))) + (is (= ":foo0" (:value (read-reply in session @id))))) + (testing "providing an ns value of a non-existing namespace falls back the last defined namespace" + (bencode/write-bencode os {"op" "eval" + "code" "(foo)" + "session" session + "id" (new-id!) + "ns" "unicorn"}) + (is (= ":foo1" (:value (read-reply in session @id))))))) (testing "load-file" (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" (new-id!)}) (read-reply in session @id) From 34993109443143142c1232fab27b87a1752f8e0c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Apr 2020 23:51:26 +0200 Subject: [PATCH 160/264] CircleCI config --- .circleci/config.yml | 9 +++++++++ .circleci/script/docker | 2 +- Dockerfile | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 191af3d8..d41b04e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,7 @@ jobs: environment: LEIN_ROOT: "true" BABASHKA_PLATFORM: linux # could be used in jar name + resource_class: large steps: - checkout - run: @@ -70,6 +71,8 @@ jobs: GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.1 BABASHKA_PLATFORM: linux # used in release script BABASHKA_TEST_ENV: native + BABASHKA_XMX: "-J-Xmx7g" + resource_class: large steps: - checkout - run: @@ -139,6 +142,8 @@ jobs: BABASHKA_PLATFORM: linux-static # used in release script BABASHKA_TEST_ENV: native BABASHKA_STATIC: true + BABASHKA_XMX: "-J-Xmx7g" + resource_class: large steps: - checkout - run: @@ -205,6 +210,8 @@ jobs: GRAALVM_HOME: /Users/distiller/graalvm-ce-java8-19.3.1/Contents/Home BABASHKA_PLATFORM: macos # used in release script BABASHKA_TEST_ENV: native + BABASHKA_XMX: "-J-Xmx7g" + resource_class: large steps: - checkout - run: @@ -259,6 +266,7 @@ jobs: command: | ./bb .circleci/script/publish_artifact.clj deploy: + resource_class: large docker: - image: circleci/clojure:lein-2.8.1 working_directory: ~/repo @@ -282,6 +290,7 @@ jobs: - ~/.m2 key: v1-dependencies-{{ checksum "project.clj" }} docker: + resource_class: large docker: - image: circleci/buildpack-deps:stretch steps: diff --git a/.circleci/script/docker b/.circleci/script/docker index d2bda10e..e615932e 100755 --- a/.circleci/script/docker +++ b/.circleci/script/docker @@ -17,7 +17,7 @@ fi if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$CIRCLE_BRANCH" = "master" ]; then echo "Building Docker image $image_name:$image_tag" echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin - docker build -t "$image_name" . + docker build -t "$image_name" --build-arg BABASHKA_XMX="-J-Xmx7g" . docker tag "$image_name:$latest_tag" "$image_name:$image_tag" # we only update latest when it's not a SNAPSHOT version if [ "false" = "$snapshot" ]; then diff --git a/Dockerfile b/Dockerfile index 5b1d5687..97b44d1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,18 @@ FROM clojure:lein-2.9.1 AS BASE +ARG BABASHKA_XMX="-J-Xmx3g" RUN apt update RUN apt install --no-install-recommends -yy curl unzip build-essential zlib1g-dev WORKDIR "/opt" RUN curl -sLO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-19.3.1/graalvm-ce-java8-linux-amd64-19.3.1.tar.gz RUN tar -xzf graalvm-ce-java8-linux-amd64-19.3.1.tar.gz + ENV GRAALVM_HOME="/opt/graalvm-ce-java8-19.3.1" ENV JAVA_HOME="/opt/graalvm-ce-java8-19.3.1/bin" ENV PATH="$PATH:$JAVA_HOME" ENV BABASHKA_STATIC="true" +ENV BABASHKA_XMX=$BABASHKA_XMX + COPY . . RUN ./script/compile From b522531e79cccb75f9d083c61f99af2965f1362d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 00:04:30 +0200 Subject: [PATCH 161/264] [#329] create non-existing ns in nREPL message --- src/babashka/impl/nrepl_server.clj | 2 +- test/babashka/impl/nrepl_server_test.clj | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 2f65dfce..22214c20 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -41,7 +41,7 @@ (defn eval-msg [ctx o msg #_threads] (try (let [ns-str (get msg :ns) - sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) nil false)) + sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) true nil)) sw (StringWriter.)] (sci/with-bindings (cond-> {sci/out sw} sci-ns (assoc vars/current-ns sci-ns)) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index 42f3bca1..f0947bbc 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -69,13 +69,14 @@ "id" (new-id!) "ns" "ns0"}) (is (= ":foo0" (:value (read-reply in session @id))))) - (testing "providing an ns value of a non-existing namespace falls back the last defined namespace" + (testing "providing an ns value of a non-existing namespace creates the namespace" (bencode/write-bencode os {"op" "eval" - "code" "(foo)" + "code" "(ns-name *ns*)" "session" session "id" (new-id!) "ns" "unicorn"}) - (is (= ":foo1" (:value (read-reply in session @id))))))) + (let [reply (read-reply in session @id)] + (is (= "unicorn" (:value reply))))))) (testing "load-file" (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" (new-id!)}) (read-reply in session @id) From 972bb77b3db1d88031ba5f9c97a732eeb3e36188 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 09:51:31 +0200 Subject: [PATCH 162/264] sci: add while macro --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 26944ee9..382dfb3a 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 26944ee9e1349fecd113ac6075bd66306ce3a6f8 +Subproject commit 382dfb3ae23493f12fb50a40e249ce47b156676d From fe981608e79126288ae9cb5d74e2071cdd649e8b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 09:59:23 +0200 Subject: [PATCH 163/264] v0.0.80 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 6d03ff2c..d33efe9e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.80-SNAPSHOT \ No newline at end of file +0.0.80 \ No newline at end of file From 9dbc916b3affd326fb894e410a015b0a9f68ae8b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 10:59:06 +0200 Subject: [PATCH 164/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index d39e547e..d33efe9e 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.79 \ No newline at end of file +0.0.80 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index d33efe9e..9a3ee0ac 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.80 \ No newline at end of file +0.0.81-SNAPSHOT \ No newline at end of file From ddfce6ab1202d36d453dcd905045a3eaab2a0a5a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 11:05:54 +0200 Subject: [PATCH 165/264] README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 52e58bcc..8752f1ba 100644 --- a/README.md +++ b/README.md @@ -897,6 +897,10 @@ user=> (hello "Alice") "Hello Alice" ``` +#### [nubank/docopt](https://github.com/nubank/docopt.clj#babashka) + +Docopt implementation in Clojure, compatible with babashka. + #### [babashka lambda layer](https://github.com/dainiusjocas/babashka-lambda-layer) Babashka Lambda runtime packaged as a Lambda layer. From e389413f6edeadda3d980b1f8f6e5a6791b371cb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 20:33:50 +0200 Subject: [PATCH 166/264] README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8752f1ba..3fef5ea4 100644 --- a/README.md +++ b/README.md @@ -725,14 +725,13 @@ with `lein repl`: (let [s (java.net.Socket. "localhost" port) out (.getOutputStream s) in (java.io.PushbackInputStream. (.getInputStream s)) - _ (b/write-bencode out {"op" "eval" "code" (pr-str expr)}) - value (get (b/read-bencode in) "value")] - (read-string value))) + _ (b/write-bencode out {"op" "eval" "code" expr}) + bytes (get (b/read-bencode in) "value")] + (String. bytes))) -(nrepl-eval 65274 '(+ 1 2 3)) ;;=> 6 +(nrepl-eval 52054 "(+ 1 2 3)") ;;=> "6" ``` - ## Differences with Clojure Babashka is implemented using the [Small Clojure From fa918c8b2a7967822595d9d854d430c57c1f84f8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 21:50:59 +0200 Subject: [PATCH 167/264] README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3fef5ea4..eccac7f5 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,6 @@ As one user described it: * Batteries included (tools.cli, cheshire, ...) * Library support via popular tools like the `clojure` CLI -Also see the [slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020) of the Babashka talk at ClojureD 2020 ([video](https://www.youtube.com/watch?v=Nw8aN-nrdEk)). - ### Non-goals * Performance1 @@ -57,8 +55,7 @@ startup time penalty. Read more about the differences with Clojure To get an overview of babashka, you can watch this talk: -[![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) - +[![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)). ## Quickstart @@ -915,8 +912,10 @@ AWS Lambda runtime doesn't support signals, therefore babashka has to disable handling of the SIGPIPE. This can be done by setting `BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER` to `true`. -### Blogs +### Articles, podcasts and videos +- [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) +- [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks - [Clojure Start Time in 2019](https://stuartsierra.com/2019/12/21/clojure-start-time-in-2019) by Stuart Sierra - [Advent of Random From 5b81a209167e1af5b120b7cbfd689b5d68a71b68 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 21:51:53 +0200 Subject: [PATCH 168/264] README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eccac7f5..811b731b 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ startup time penalty. Read more about the differences with Clojure ### Talk -To get an overview of babashka, you can watch this 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)): -[![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)). +[![Babashka at ClojureD 2020](https://img.youtube.com/vi/Nw8aN-nrdEk/0.jpg)](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ## Quickstart From 2f28804ea65dabd28728f68824dcde5f000d9292 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 21:53:11 +0200 Subject: [PATCH 169/264] README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 811b731b..da2c74e9 100644 --- a/README.md +++ b/README.md @@ -914,8 +914,8 @@ handling of the SIGPIPE. This can be done by setting ### Articles, podcasts and videos -- [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) -- [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) +- [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) with Jacek Schae interviewing Michiel Borkent +- [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) by Michiel Borkent - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks - [Clojure Start Time in 2019](https://stuartsierra.com/2019/12/21/clojure-start-time-in-2019) by Stuart Sierra - [Advent of Random From 8c1077af00c818ade9e646dfe1297bbe24b17f4d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 21:53:54 +0200 Subject: [PATCH 170/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da2c74e9..699d1d23 100644 --- a/README.md +++ b/README.md @@ -912,7 +912,7 @@ AWS Lambda runtime doesn't support signals, therefore babashka has to disable handling of the SIGPIPE. This can be done by setting `BABASHKA_DISABLE_PIPE_SIGNAL_HANDLER` to `true`. -### Articles, podcasts and videos +## Articles, podcasts and videos - [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) with Jacek Schae interviewing Michiel Borkent - [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) by Michiel Borkent From 74d3cf4140e1dcfb7d8172d683353ea106f3165c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Apr 2020 22:11:09 +0200 Subject: [PATCH 171/264] docker xmx --- .circleci/script/docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/script/docker b/.circleci/script/docker index e615932e..d7410e0a 100755 --- a/.circleci/script/docker +++ b/.circleci/script/docker @@ -17,7 +17,7 @@ fi if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$CIRCLE_BRANCH" = "master" ]; then echo "Building Docker image $image_name:$image_tag" echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin - docker build -t "$image_name" --build-arg BABASHKA_XMX="-J-Xmx7g" . + docker build -t "$image_name" --build-arg BABASHKA_XMX="-J-Xmx6900m" . docker tag "$image_name:$latest_tag" "$image_name:$image_tag" # we only update latest when it's not a SNAPSHOT version if [ "false" = "$snapshot" ]; then From fab7fedfeaba6944b4ad24f9f02f00ba9e24d1c1 Mon Sep 17 00:00:00 2001 From: Rovanion Luckey Date: Tue, 7 Apr 2020 17:13:05 +0200 Subject: [PATCH 172/264] Added two examples on how to construct a classpath to README.md (#334) --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/README.md b/README.md index 699d1d23..53b82d32 100644 --- a/README.md +++ b/README.md @@ -455,6 +455,28 @@ $ bb --classpath src --main my.namespace Hello from my namespace! ``` +So if you have a larger script with a classic Clojure project layout like + +```shellsession +$ tree -L 3 +├── deps.edn +├── README +├── src +│   └── project_namespace +│   ├── main.clj +│   └── utilities.clj +└── test + └── project_namespace + ├── test_main.clj + └── test_utilities.clj +``` +Then you can tell Babashka to include both the `src` and `test` +folders in the classpath and start a socket REPL by running: + +```shellsession +$ bb --classpath src:test --socket-repl 1666 +``` + Note that you can use the `clojure` tool to produce classpaths and download dependencies: ``` shellsession @@ -512,6 +534,46 @@ Hello from gist script! nil ``` +You can also use for example `deps.clj` to produce the classpath for a +`babashka` REPL: + +```shellsession +$ cat script/start-repl.sh +#!/bin/sh -e +git_root=$(git rev-parse --show-toplevel) +export BABASHKA_CLASSPATH=$("$git_root"/script/deps.clj -Spath) +bb --socket-repl 1666 +$ ./script/start-repl.sh +Babashka socket REPL started at localhost:1666 +``` + +Now, given that your `deps.edn` and source tree looks something like + +```shellsession +$ cat deps.edn +{:paths ["src" "test"] + :deps {}} +$ tree -L 3 +├── deps.edn +├── README +├── script +│   ├── deps.clj +│   └── start-repl.sh +├── src +│   └── project_namespace +│   ├── main.clj +│   └── utilities.clj +└── test + └── project_namespace + ├── test_main.clj + └── test_utilities.clj + +``` + +you should now be able to `(require '[multi-machine-rsync.utilities :as util])` +in your REPL and the source code in `/src/multi_machine_rsync/utilities.clj` +will be evaluated and made available through the symbol `util`. + ## Uberscript The `--uberscript` option collects the expressions in From e89782686e0974eb9d778a2011b3f77bef6fa804 Mon Sep 17 00:00:00 2001 From: Will Date: Tue, 7 Apr 2020 10:44:51 -0700 Subject: [PATCH 173/264] correct medley deps in README (#335) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53b82d32..da8d8fcd 100644 --- a/README.md +++ b/README.md @@ -850,13 +850,13 @@ Ran 1 tests containing 0 assertions. Requires `bb` >= v0.0.71. Latest coordinates checked with with bb: ``` clojure -{:git/url "https://github.com/weavejester" :sha "a4e5fb5383f5c0d83cb2d005181a35b76d8a136d"} +{:git/url "https://github.com/weavejester/medley" :sha "a4e5fb5383f5c0d83cb2d005181a35b76d8a136d"} ``` Example: ``` shell -$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {medley {:git/url "https://github.com/weavejester" :sha "a4e5fb5383f5c0d83cb2d005181a35b76d8a136d"}}}') +$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {medley {:git/url "https://github.com/weavejester/medley" :sha "a4e5fb5383f5c0d83cb2d005181a35b76d8a136d"}}}') $ bb -e "(require '[medley.core :as m]) (m/index-by :id [{:id 1} {:id 2}])" {1 {:id 1}, 2 {:id 2}} From 110f6d76447f1d21736f8d7e204a0db8afcd9742 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 21:18:25 +0200 Subject: [PATCH 174/264] [#336] Add java.lang.Runtime to support shutdown hooks (#338) --- src/babashka/impl/classes.clj | 1 + src/babashka/impl/sigint_handler.clj | 14 +++++++++++ src/babashka/main.clj | 3 +++ test/babashka/http_connection_test.clj | 10 ++++---- test/babashka/main_test.clj | 9 +++++-- .../scripts/download_and_extract_zip.bb | 7 +++--- test/babashka/scripts/interrupt_handler.bb | 6 +++++ test/babashka/shutdown_hook_test.clj | 24 +++++++++++++++++++ 8 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 src/babashka/impl/sigint_handler.clj create mode 100644 test/babashka/scripts/interrupt_handler.bb create mode 100644 test/babashka/shutdown_hook_test.clj diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index fc500fe1..64e04cdc 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -39,6 +39,7 @@ java.lang.Long java.lang.NumberFormatException java.lang.Math + java.lang.Runtime java.lang.RuntimeException java.util.concurrent.LinkedBlockingQueue java.lang.Object diff --git a/src/babashka/impl/sigint_handler.clj b/src/babashka/impl/sigint_handler.clj new file mode 100644 index 00000000..9708bc59 --- /dev/null +++ b/src/babashka/impl/sigint_handler.clj @@ -0,0 +1,14 @@ +(ns babashka.impl.sigint-handler + {:no-doc true} + (:import [sun.misc Signal] + [sun.misc SignalHandler])) + +(set! *warn-on-reflection* true) + +(defn handle-sigint! [] + (Signal/handle + (Signal. "INT") + (reify SignalHandler + (handle [_ _] + ;; This is needed to run shutdown hooks on interrupt, System/exit triggers those + (System/exit 0))))) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index e893bd52..caa3ebdd 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -18,6 +18,7 @@ [babashka.impl.nrepl-server :as nrepl-server] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] [babashka.impl.repl :as repl] + [babashka.impl.sigint-handler :as sigint-handler] [babashka.impl.socket-repl :as socket-repl] [babashka.impl.test :as t] [babashka.impl.tools.cli :refer [tools-cli-namespace]] @@ -303,6 +304,7 @@ Everything after that is bound to *command-line-args*.")) (defn main [& args] (handle-pipe!) + (sigint-handler/handle-sigint!) #_(binding [*out* *err*] (prn "M" (meta (get bindings 'future)))) (binding [*unrestricted* true] @@ -368,6 +370,7 @@ Everything after that is bound to *command-line-args*.")) Math java.lang.Math NumberFormatException java.lang.NumberFormatException Object java.lang.Object + Runtime java.lang.Runtime RuntimeException java.lang.RuntimeException ProcessBuilder java.lang.ProcessBuilder String java.lang.String diff --git a/test/babashka/http_connection_test.clj b/test/babashka/http_connection_test.clj index ec78fa12..25a5338e 100644 --- a/test/babashka/http_connection_test.clj +++ b/test/babashka/http_connection_test.clj @@ -1,14 +1,14 @@ (ns babashka.http-connection-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 bb [& args] (apply tu/bb nil (map str args))) (deftest open-connection-test - (is (= "\"1\"" (str/trim (bb "-e" " + (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\"))] (.setConnectTimeout conn 1000) @@ -18,4 +18,6 @@ err (.getErrorStream conn) response (json/decode (slurp is) true)] (-> response :args :foo))) -"))))) +"))) + (catch Exception e + (str/includes? (str e) "timed out"))))) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 12c9d514..749f5ce3 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -9,6 +9,9 @@ [clojure.test :as test :refer [deftest is testing]] [sci.core :as sci])) +#_(defmethod clojure.test/report :begin-test-var [m] + (println (-> m :var meta :name))) + (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) @@ -164,7 +167,7 @@ (deftest future-test (is (= 6 (bb nil "@(future (+ 1 2 3))")))) - + (deftest promise-test (is (= :timeout (bb nil "(deref (promise) 1 :timeout)"))) (is (= :ok (bb nil "(let [x (promise)] @@ -376,7 +379,9 @@ (is v)))) (deftest download-and-extract-test - (is (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb"))))) + (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")))))) (deftest get-message-on-exception-info-test (is "foo" (bb nil "(try (throw (ex-info \"foo\" {})) (catch Exception e (.getMessage e)))"))) diff --git a/test/babashka/scripts/download_and_extract_zip.bb b/test/babashka/scripts/download_and_extract_zip.bb index fd2bc150..befe9258 100644 --- a/test/babashka/scripts/download_and_extract_zip.bb +++ b/test/babashka/scripts/download_and_extract_zip.bb @@ -11,7 +11,9 @@ tmp-dir (System/getProperty "java.io.tmpdir") zip-file (io/file tmp-dir "bb-0.0.78.zip") source (URL. (format "https://github.com/borkdude/babashka/releases/download/v0.0.78/babashka-0.0.78-%s-amd64.zip" os)) - conn ^HttpURLConnection (.openConnection ^URL source)] + conn ^HttpURLConnection (.openConnection ^URL source) + _ (.setConnectTimeout conn 2000) + _ (.setReadTimeout conn 2000)] (.connect conn) (with-open [is (.getInputStream conn)] (io/copy is zip-file)) @@ -26,6 +28,3 @@ (.delete bb-file) (.delete zip-file) (println out)))) - - - diff --git a/test/babashka/scripts/interrupt_handler.bb b/test/babashka/scripts/interrupt_handler.bb new file mode 100644 index 00000000..02291139 --- /dev/null +++ b/test/babashka/scripts/interrupt_handler.bb @@ -0,0 +1,6 @@ +(require '[babashka.signal :as signal]) + +(signal/add-interrupt-handler! :quit (fn [k] (println "bye1" k))) +(signal/add-interrupt-handler! :quit2 (fn [k] (println "bye2" k))) + +(System/exit 0) diff --git a/test/babashka/shutdown_hook_test.clj b/test/babashka/shutdown_hook_test.clj new file mode 100644 index 00000000..8c2c1f82 --- /dev/null +++ b/test/babashka/shutdown_hook_test.clj @@ -0,0 +1,24 @@ +(ns babashka.shutdown-hook-test + {:no-doc true} + (:import [java.nio.charset Charset]) + (:require [babashka.test-utils :as tu] + [clojure.java.io :as io] + [clojure.test :refer [deftest is]])) + +(defn- stream-to-string + ([in] (stream-to-string in (.name (Charset/defaultCharset)))) + ([in enc] + (with-open [bout (java.io.StringWriter.)] + (io/copy in bout :encoding enc) + (.toString bout)))) + +(deftest interrupt-handler-test + (let [script "(-> (Runtime/getRuntime) (.addShutdownHook (Thread. #(println \"bye\"))))" + pb (ProcessBuilder. (if tu/jvm? + ["lein" "bb" "-e" script] + ["./bb" "-e" script])) + process (.start pb) + output (.getInputStream process)] + (when-let [s (not-empty (stream-to-string (.getErrorStream process)))] + (prn "ERROR:" s)) + (is (= "bye\n" (stream-to-string output))))) From 2a1ad4e84fe69a8da2c556eeab9459ba0cc2f530 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 21:18:56 +0200 Subject: [PATCH 175/264] Shutdown hooks docs --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index da8d8fcd..fec578d4 100644 --- a/README.md +++ b/README.md @@ -769,6 +769,17 @@ This can be useful for talking to Docker: :RepoTags) ;;=> ["borkdude/babashka:latest"] ``` +## Shutdown hook + +Adding a shutdown hook allows you to execute some code before the script exits. + +``` clojure +$ bb -e '(-> (Runtime/getRuntime) (.addShutdownHook (Thread. #(println "bye"))))' +bye +``` + +This also works when the script is interrupted with ctrl-c. + ## Bencode Babashka comes with the [nrepl/bencode](https://github.com/nrepl/bencode) From fa24ea140866fe99c899c0f50250f5700557a097 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 22:17:12 +0200 Subject: [PATCH 176/264] v0.0.81 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 9a3ee0ac..97452761 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.81-SNAPSHOT \ No newline at end of file +0.0.81 \ No newline at end of file From 1e865d5c11c0fd787ee40ef6efe5fd56e034d084 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 22:49:46 +0200 Subject: [PATCH 177/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index d33efe9e..97452761 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.80 \ No newline at end of file +0.0.81 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 97452761..74f0fc13 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.81 \ No newline at end of file +0.0.82-SNAPSHOT \ No newline at end of file From 822bae9de356813d6458a8ba46607ea00ef3ebcd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 23:12:16 +0200 Subject: [PATCH 178/264] Print test names --- test/babashka/main_test.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 749f5ce3..51c626b4 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -9,8 +9,9 @@ [clojure.test :as test :refer [deftest is testing]] [sci.core :as sci])) -#_(defmethod clojure.test/report :begin-test-var [m] - (println (-> m :var meta :name))) +(defmethod clojure.test/report :begin-test-var [m] + (println "===" (-> m :var meta :name)) + (println)) (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) From 4aa71236e8fb1cd37e90598aaa815fc07367614c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 9 Apr 2020 21:58:02 +0200 Subject: [PATCH 179/264] sci: readme --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 382dfb3a..6b970e5a 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 382dfb3ae23493f12fb50a40e249ce47b156676d +Subproject commit 6b970e5ad9fa750440b8cb6b5c39f00ccbf43065 From 8c6f9727270b801fe055f764583186408a8a328d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 9 Apr 2020 22:00:53 +0200 Subject: [PATCH 180/264] README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index fec578d4..454c44ae 100644 --- a/README.md +++ b/README.md @@ -979,6 +979,10 @@ Babashka Lambda runtime packaged as a Lambda layer. Github Action to create a git tag + release when pushed to master. Written in babashka. +#### [justone/bb-scripts](https://github.com/justone/bb-scripts) + +A collection of scripts developed by [https://github.com/justone](@justone). + ## Package babashka script as a AWS Lambda AWS Lambda runtime doesn't support signals, therefore babashka has to disable @@ -987,6 +991,7 @@ handling of the SIGPIPE. This can be done by setting ## Articles, podcasts and videos +- [Dutch Clojure Meetup: implementing an nREPL server for babashka](https://youtu.be/0YmZYnwyHHc) - [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) with Jacek Schae interviewing Michiel Borkent - [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) by Michiel Borkent - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks From 3994dd0a9494e1ac49242585f0ab742f8c07ade8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 9 Apr 2020 22:02:54 +0200 Subject: [PATCH 181/264] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 454c44ae..140c7192 100644 --- a/README.md +++ b/README.md @@ -991,7 +991,7 @@ handling of the SIGPIPE. This can be done by setting ## Articles, podcasts and videos -- [Dutch Clojure Meetup: implementing an nREPL server for babashka](https://youtu.be/0YmZYnwyHHc) +- [Implementing an nREPL server for babashka](https://youtu.be/0YmZYnwyHHc): impromptu presentation by Michiel Borkent at the online [Dutch Clojure Meetup](http://meetup.com/The-Dutch-Clojure-Meetup) - [ClojureScript podcast](https://soundcloud.com/user-959992602/s3-e5-babashka-with-michiel-borkent) with Jacek Schae interviewing Michiel Borkent - [Babashka talk at ClojureD](https://www.youtube.com/watch?v=Nw8aN-nrdEk) ([slides](https://speakerdeck.com/borkdude/babashka-and-the-small-clojure-interpreter-at-clojured-2020)) by Michiel Borkent - [Babashka: a quick example](https://juxt.pro/blog/posts/babashka.html) by Malcolm Sparks From 6a2fc4a7d839f33371b148244e70df7b9d776ea2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 9 Apr 2020 22:11:55 +0200 Subject: [PATCH 182/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 6b970e5a..31f40662 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 6b970e5ad9fa750440b8cb6b5c39f00ccbf43065 +Subproject commit 31f406625481f9e74ff6ead730595cd8c7892955 From 84fddd8766515501c8518e8dd208660269ab3f89 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 10 Apr 2020 09:06:00 +0200 Subject: [PATCH 183/264] README: adapt quickstart --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 140c7192..d2b63c36 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,8 @@ To get an overview of babashka, you can watch this talk ([slides](https://speake ## Quickstart ``` shellsession -$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install) +$ curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install -o install-babashka +$ chmod +x install-babashka && ./install-babashka $ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' ("doc" "resources" "sci" "script" "src" "target" "test") bb took 4ms. From dc68b5fa4f1c3721ccf024a8e80ef1e950173504 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 10 Apr 2020 11:52:26 +0200 Subject: [PATCH 184/264] babashka.curl: fix borkdude/babashka.curl#11 --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 48287b00..ebda9028 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 48287b007ea6e53280413dd70351a887210e3cf2 +Subproject commit ebda9028f29100ee4233358ac596ab3cef372b52 From 7e30c40dd955148e65c040ab936225c57f213249 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 10 Apr 2020 14:29:10 +0200 Subject: [PATCH 185/264] nREPL server cleanup --- src/babashka/impl/nrepl_server.clj | 101 +++++++++------------------ test/babashka/shutdown_hook_test.clj | 2 +- 2 files changed, 35 insertions(+), 68 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 22214c20..5d915bfa 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -17,10 +17,8 @@ (defn response-for [old-msg msg] (let [session (get old-msg :session "none") - m (assoc msg "session" session) - id (get old-msg :id "unknown") - m (assoc m "id" id)] - m)) + id (get old-msg :id "unknown")] + (assoc msg "session" session "id" id))) (defn send [^OutputStream os msg] ;;(when @dev? (prn "Sending" msg)) @@ -38,7 +36,7 @@ "status" #{"eval-error"}})) (send os (response-for msg {"status" #{"done"}})))) -(defn eval-msg [ctx o msg #_threads] +(defn eval-msg [ctx o msg] (try (let [ns-str (get msg :ns) sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) true nil)) @@ -46,32 +44,27 @@ (sci/with-bindings (cond-> {sci/out sw} sci-ns (assoc vars/current-ns sci-ns)) (when @dev? (println "current ns" (vars/current-ns-name))) - (let [session (get msg :session "none") - id (get msg :id "unknown")] - (when @dev? (println "Registering thread for" (str session "-" id))) - ;; (swap! threads assoc [session id] (Thread/currentThread)) - (let [code-str (get msg :code) - value (if (str/blank? code-str) - ::nil - (eval-string* ctx code-str)) - out-str (not-empty (str sw)) - env (:env ctx)] - (swap! env update-in [:namespaces 'clojure.core] - (fn [core] - (assoc core - '*1 value - '*2 (get core '*1) - '*3 (get core '*2)))) - (when @dev? (println "out str:" out-str)) - (when out-str - (send o (response-for msg {"out" out-str}))) - (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} - (not (identical? value ::nil)) (assoc "value" (pr-str value))))) - (send o (response-for msg {"status" #{"done"}})))))) + (let [code-str (get msg :code) + value (if (str/blank? code-str) + ::nil + (eval-string* ctx code-str)) + out-str (not-empty (str sw)) + env (:env ctx)] + (swap! env update-in [:namespaces 'clojure.core] + (fn [core] + (assoc core + '*1 value + '*2 (get core '*1) + '*3 (get core '*2)))) + (when @dev? (println "out str:" out-str)) + (when out-str + (send o (response-for msg {"out" out-str}))) + (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} + (not (identical? value ::nil)) (assoc "value" (pr-str value))))) + (send o (response-for msg {"status" #{"done"}}))))) (catch Exception ex (swap! (:env ctx) update-in [:namespaces 'clojure.core] - (fn [core] - (assoc core '*e ex))) + assoc '*e ex) (send-exception o msg ex)))) (defn fully-qualified-syms [ctx ns-sym] @@ -127,17 +120,6 @@ (send o (response-for msg {"completions" [] "status" #{"done"}}))))) -;; GraalVM doesn't support the .stop method on Threads, so for now we will have to live without interrupt -#_(defn interrupt [_ctx os msg threads] - (let [session (get msg :session "none") - id (get msg :interrupt-id)] - (when-let [t (get @threads [session id])] - (when @dev? (println "Killing thread" (str session "-" id))) - (try (.stop ^java.lang.Thread t) - (catch Throwable e - (println e)))) - (send os (response-for msg {"status" #{"done"}})))) - (defn read-msg [msg] (-> (zipmap (map keyword (keys msg)) (map #(if (bytes? %) @@ -145,7 +127,7 @@ %) (vals msg))) (update :op keyword))) -(defn session-loop [ctx ^InputStream is os id #_threads] +(defn session-loop [ctx ^InputStream is os id] (when @dev? (println "Reading!" id (.available is))) (when-let [msg (try (read-bencode is) (catch EOFException _ @@ -157,57 +139,43 @@ (when @dev? (println "Cloning!")) (let [id (str (java.util.UUID/randomUUID))] (send os (response-for msg {"new-session" id "status" #{"done"}})) - (recur ctx is os id #_threads))) + (recur ctx is os id))) :eval (do - (eval-msg ctx os msg #_threads) - (recur ctx is os id #_threads)) + (eval-msg ctx os msg) + (recur ctx is os id)) :load-file (let [file (:file msg) msg (assoc msg :code file)] - (eval-msg ctx os msg #_threads) - (recur ctx is os id #_threads)) + (eval-msg ctx os msg) + (recur ctx is os id)) :complete (do (complete ctx os msg) - (recur ctx is os id #_threads)) - ;; :interrupt (do - ;; (interrupt ctx os msg threads) - ;; (recur ctx is os id threads)) + (recur ctx is os id)) :describe (do (send os (response-for msg {"status" #{"done"} - "aux" {} "ops" (zipmap #{"clone" "eval" "load-file" "complete" "describe"} - (repeat {})) - "versions" {} #_{"nrepl" {"major" "0" - "minor" "4" - "incremental" "0" - "qualifier" ""} - "clojure" - {"*clojure-version*" - (zipmap (map name (keys *clojure-version*)) - (vals *clojure-version*))}}})) - (recur ctx is os id #_threads)) + (repeat {}))})) + (recur ctx is os id)) ;; fallback (do (when @dev? (println "Unhandled message" msg)) (send os (response-for msg {"status" #{"error" "unknown-op" "done"}})) - (recur ctx is os id #_threads)))))) + (recur ctx is os id)))))) (defn listen [ctx ^ServerSocket listener] (when @dev? (println "Listening")) (let [client-socket (.accept listener) in (.getInputStream client-socket) in (PushbackInputStream. in) - out (.getOutputStream client-socket) - #_threads #_(atom {})] + out (.getOutputStream client-socket)] (when @dev? (println "Connected.")) (sci/future (sci/binding ;; allow *ns* to be set! inside future [vars/current-ns (vars/->SciNamespace 'user nil) sci/print-length @sci/print-length] - (session-loop ctx in out "pre-init" #_threads))) + (session-loop ctx in out "pre-init"))) (recur ctx listener))) - (def server (atom nil)) (defn stop-server! [] @@ -224,7 +192,6 @@ (Integer. ^String (second parts))]) host+port (if-not address (str "localhost:" port) host+port)] - #_(complete ctx nil {:symbol "json"}) (println "Starting nREPL server at" host+port) (let [socket-server (new ServerSocket port 0 address)] (reset! server socket-server) diff --git a/test/babashka/shutdown_hook_test.clj b/test/babashka/shutdown_hook_test.clj index 8c2c1f82..71995c97 100644 --- a/test/babashka/shutdown_hook_test.clj +++ b/test/babashka/shutdown_hook_test.clj @@ -12,7 +12,7 @@ (io/copy in bout :encoding enc) (.toString bout)))) -(deftest interrupt-handler-test +(deftest shutdown-hook-test (let [script "(-> (Runtime/getRuntime) (.addShutdownHook (Thread. #(println \"bye\"))))" pb (ProcessBuilder. (if tu/jvm? ["lein" "bb" "-e" script] From 1c467080fad92231001286317a1a47a27ff6c4fd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 10 Apr 2020 23:39:04 +0200 Subject: [PATCH 186/264] borkdude/babashka.curl#13 --- babashka.curl | 2 +- script/lib_tests/babashka_curl_test | 2 +- src/babashka/impl/classes.clj | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/babashka.curl b/babashka.curl index ebda9028..4b77c8c5 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit ebda9028f29100ee4233358ac596ab3cef372b52 +Subproject commit 4b77c8c5a31eefb46d4977d356f9cfa5546db6a6 diff --git a/script/lib_tests/babashka_curl_test b/script/lib_tests/babashka_curl_test index 3605234f..84f60151 100755 --- a/script/lib_tests/babashka_curl_test +++ b/script/lib_tests/babashka_curl_test @@ -2,7 +2,7 @@ set -eo pipefail -export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {babasha.curl {:git/url "https://github.com/borkdude/babashka.curl" :sha "6a4de335fa0ba75814567e013a286cafcabff8c0"}}}' -Spath) +export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {babasha.curl {:local/root "babashka.curl"}}}' -Spath) if [ "$BABASHKA_TEST_ENV" = "native" ]; then BB_CMD="./bb" diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 64e04cdc..aa97b177 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -25,6 +25,7 @@ java.io.FileReader java.io.PushbackInputStream java.io.Reader + java.io.SequenceInputStream java.io.StringReader java.io.StringWriter java.io.Writer From 9f199ddef798f9ea9f488023af3758d402a1c729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Szabo?= Date: Sat, 11 Apr 2020 04:47:06 -0300 Subject: [PATCH 187/264] Send bencode using BufferedOutputStream (#342) This new implementation is faster because you only flush when you issue `.flush`, or until the buffer is full. Some simple experiments with Chlorine confirmed that small messages are being received in a whole block, instead of fragmented. --- src/babashka/impl/nrepl_server.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 5d915bfa..8b9026ac 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -7,7 +7,7 @@ [sci.impl.interpreter :refer [eval-string*]] [sci.impl.utils :as sci-utils] [sci.impl.vars :as vars]) - (:import [java.io StringWriter OutputStream InputStream PushbackInputStream EOFException] + (:import [java.io StringWriter OutputStream InputStream PushbackInputStream EOFException BufferedOutputStream] [java.net ServerSocket])) (set! *warn-on-reflection* true) @@ -166,7 +166,8 @@ (let [client-socket (.accept listener) in (.getInputStream client-socket) in (PushbackInputStream. in) - out (.getOutputStream client-socket)] + out (.getOutputStream client-socket) + out (BufferedOutputStream. out)] (when @dev? (println "Connected.")) (sci/future (sci/binding From fb53e05ba724b9b4ac3dfe139ce635ac6b672fe7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 12:24:56 +0200 Subject: [PATCH 188/264] [#340] fix interop with PushbackInputStream --- project.clj | 2 ++ sci | 2 +- test/babashka/main_test.clj | 10 ++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/project.clj b/project.clj index 8dbf52a2..87d98573 100644 --- a/project.clj +++ b/project.clj @@ -8,6 +8,8 @@ :license {:name "Eclipse Public License 1.0" :url "http://opensource.org/licenses/eclipse-1.0.php"} :source-paths ["src" "sci/src" "babashka.curl/src"] + ;; for debugging Reflector.java code: + ;; :java-source-paths ["sci/reflector/src-java"] :resource-paths ["resources" "sci/resources"] :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] diff --git a/sci b/sci index 31f40662..f5161caf 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 31f406625481f9e74ff6ead730595cd8c7892955 +Subproject commit f5161cafd86bdd4a139d5427a26e5a3fa87734b1 diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 51c626b4..7161b483 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -387,8 +387,14 @@ (deftest get-message-on-exception-info-test (is "foo" (bb nil "(try (throw (ex-info \"foo\" {})) (catch Exception e (.getMessage e)))"))) +(deftest pushback-reader-test + (is (= "foo" (bb nil " +(require '[clojure.java.io :as io]) +(let [pb (java.io.PushbackInputStream. (java.io.ByteArrayInputStream. (.getBytes \"foo\")))] + (.unread pb (.read pb)) + (slurp pb))")))) + ;;;; Scratch (comment - (dotimes [_ 10] (wait-for-port-test)) - ) + (dotimes [_ 10] (wait-for-port-test))) From 01f5d01aa2889084f85b4da6c5f8770a940eca87 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 12:25:23 +0200 Subject: [PATCH 189/264] v0.0.82 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 74f0fc13..85013834 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.82-SNAPSHOT \ No newline at end of file +0.0.82 \ No newline at end of file From 9396258d3e13cad1dfc8731b38e3ca2cca1149a9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 12:35:18 +0200 Subject: [PATCH 190/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 97452761..85013834 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.81 \ No newline at end of file +0.0.82 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 85013834..aa5b4be9 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.82 \ No newline at end of file +0.0.83-SNAPSHOT \ No newline at end of file From 4109aa52646c2ea9fd20edb98bf4817d3562bd2b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 20:47:24 +0200 Subject: [PATCH 191/264] Bump edamame, fixes #347 --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- script/lib_tests/regal_test | 13 +++++++++++-- test/babashka/main_test.clj | 1 + 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/deps.edn b/deps.edn index c09a693c..61c36244 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {:paths ["src" "sci/src" "babashka.curl/src" "resources" "sci/resources"], :deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}, org.clojure/tools.reader {:mvn/version "1.3.2"}, - borkdude/edamame {:mvn/version "0.0.10"}, + borkdude/edamame {:mvn/version "0.0.11-alpha.6"}, borkdude/graal.locking {:mvn/version "0.0.2"}, borkdude/sci.impl.reflector {:mvn/version "0.0.1"} org.clojure/core.async {:mvn/version "1.0.567"}, diff --git a/project.clj b/project.clj index 87d98573..de221f34 100644 --- a/project.clj +++ b/project.clj @@ -13,7 +13,7 @@ :resource-paths ["resources" "sci/resources"] :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] - [borkdude/edamame "0.0.10"] + [borkdude/edamame "0.0.11-alpha.6"] [borkdude/graal.locking "0.0.2"] [borkdude/sci.impl.reflector "0.0.1"] [org.clojure/core.async "1.0.567"] diff --git a/sci b/sci index f5161caf..1b106678 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit f5161cafd86bdd4a139d5427a26e5a3fa87734b1 +Subproject commit 1b106678929b46a8bc74364b3b0c6e2fc53eaab8 diff --git a/script/lib_tests/regal_test b/script/lib_tests/regal_test index ad313fe9..4073c9e6 100755 --- a/script/lib_tests/regal_test +++ b/script/lib_tests/regal_test @@ -2,7 +2,7 @@ set -eo pipefail -export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "d4e25e186f7b9705ebb3df6b21c90714d278efb7"}}}' -Spath)" +export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {regal {:git/url "https://github.com/lambdaisland/regal" :sha "b059fdb06d5586a9a04c27e7b011c467ad8546db"}}}' -Spath)" if [ "$BABASHKA_TEST_ENV" = "native" ]; then BB_CMD="./bb" @@ -10,4 +10,13 @@ else BB_CMD="lein bb" fi -$BB_CMD "(require '[lambdaisland.regal :as re]) (re/regex [:range \a \z])" +$BB_CMD " +(require '[lambdaisland.regal :as regal]) +(def r [:cat + [:+ [:class [\a \z]]] + \"=\" + [:+ [:not \=]]]) + +(prn (regal/regex r)) +(prn (re-matches (regal/regex r) \"foo=bar\")) +" diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 7161b483..10d41ac7 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -247,6 +247,7 @@ (deftest reader-conditionals-test (is (= :hello (bb nil "#?(:bb :hello :default :bye)"))) + (is (= :hello (bb nil "#? (:bb :hello :default :bye)"))) (is (= :hello (bb nil "#?(:clj :hello :bb :bye)"))) (is (= [1 2] (bb nil "[1 2 #?@(:bb [] :clj [1])]")))) From 56a798135c183265127154ce77fcdec1a0bdd4aa Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 21:10:21 +0200 Subject: [PATCH 192/264] [#345] test for .deleteOnExit --- test/babashka/main_test.clj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 10d41ac7..fa58881f 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -395,6 +395,13 @@ (.unread pb (.read pb)) (slurp pb))")))) +(deftest delete-on-exit-test + (when test-utils/native? + (let [f (java.io.File/createTempFile "foo" "bar") + p (.getPath f)] + (bb nil (format "(.deleteOnExit (io/file \"%s\"))" p)) + (is (false? (.exists f)))))) + ;;;; Scratch (comment From e2bdd7eae231f63e52760daaf5d419d674957ba0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 21:36:33 +0200 Subject: [PATCH 193/264] [#348] nrepl: support multiple top level expressions --- src/babashka/impl/nrepl_server.clj | 55 +++++++++++++----------- test/babashka/impl/nrepl_server_test.clj | 10 ++++- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 8b9026ac..db62b227 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -3,8 +3,10 @@ (:refer-clojure :exclude [send future binding]) (:require [babashka.impl.bencode.core :refer [write-bencode read-bencode]] [clojure.string :as str] + [clojure.tools.reader.reader-types :as r] [sci.core :as sci] - [sci.impl.interpreter :refer [eval-string*]] + [sci.impl.interpreter :refer [eval-string* eval-form]] + [sci.impl.parser :as p] [sci.impl.utils :as sci-utils] [sci.impl.vars :as vars]) (:import [java.io StringWriter OutputStream InputStream PushbackInputStream EOFException BufferedOutputStream] @@ -38,30 +40,35 @@ (defn eval-msg [ctx o msg] (try - (let [ns-str (get msg :ns) - sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) true nil)) - sw (StringWriter.)] - (sci/with-bindings (cond-> {sci/out sw} + (let [code-str (get msg :code) + reader (r/indexing-push-back-reader (r/string-push-back-reader code-str)) + ns-str (get msg :ns) + sci-ns (when ns-str (sci-utils/namespace-object (:env ctx) (symbol ns-str) true nil))] + (when @dev? (println "current ns" (vars/current-ns-name))) + (sci/with-bindings (cond-> {} sci-ns (assoc vars/current-ns sci-ns)) - (when @dev? (println "current ns" (vars/current-ns-name))) - (let [code-str (get msg :code) - value (if (str/blank? code-str) - ::nil - (eval-string* ctx code-str)) - out-str (not-empty (str sw)) - env (:env ctx)] - (swap! env update-in [:namespaces 'clojure.core] - (fn [core] - (assoc core - '*1 value - '*2 (get core '*1) - '*3 (get core '*2)))) - (when @dev? (println "out str:" out-str)) - (when out-str - (send o (response-for msg {"out" out-str}))) - (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} - (not (identical? value ::nil)) (assoc "value" (pr-str value))))) - (send o (response-for msg {"status" #{"done"}}))))) + (loop [] + (let [sw (StringWriter.) + form (p/parse-next ctx reader) + value (if (identical? :edamame.impl.parser/eof form) ::nil + (sci/with-bindings {sci/out sw} + (eval-form ctx form))) + out-str (not-empty (str sw)) + env (:env ctx)] + (swap! env update-in [:namespaces 'clojure.core] + (fn [core] + (assoc core + '*1 value + '*2 (get core '*1) + '*3 (get core '*2)))) + (when @dev? (println "out str:" out-str)) + (when out-str + (send o (response-for msg {"out" out-str}))) + (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} + (not (identical? value ::nil)) (assoc "value" (pr-str value))))) + (when (not (identical? ::nil value)) + (recur))))) + (send o (response-for msg {"status" #{"done"}}))) (catch Exception ex (swap! (:env ctx) update-in [:namespaces 'clojure.core] assoc '*e ex) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index f0947bbc..0892f9d7 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -76,7 +76,15 @@ "id" (new-id!) "ns" "unicorn"}) (let [reply (read-reply in session @id)] - (is (= "unicorn" (:value reply))))))) + (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)" + "session" session + "id" (new-id!)}) + (let [reply-1 (read-reply in session @id) + reply-2 (read-reply in session @id)] + (is (= "6" (:value reply-1) (:value reply-2)))))) (testing "load-file" (bencode/write-bencode os {"op" "load-file" "file" "(ns foo) (defn foo [] :foo)" "session" session "id" (new-id!)}) (read-reply in session @id) From bf958b03bb23cfa4bb46220161cf4e0d933865eb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 21:45:55 +0200 Subject: [PATCH 194/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 1b106678..7ac60d81 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 1b106678929b46a8bc74364b3b0c6e2fc53eaab8 +Subproject commit 7ac60d818d97895d275fdd58a4cc677515d26f74 From 50fa881153da505f4a0d14a1dc7ccbae8bc6d438 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 11 Apr 2020 23:25:22 +0200 Subject: [PATCH 195/264] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5c230d19..e3e48050 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,7 @@ ## v0.0.44 - 0.0.45 - #173: Rename `*in*` to `*input*` (in the `user` namespace). The reason for - this is that itt shadowed `clojure.core/*in*` when used unqualified. + this is that it shadowed `clojure.core/*in*` when used unqualified. ## v0.0.43 - #160: Add support for `java.lang.ProcessBuilder`. See docs. This replaces the From b0a3549babff0ac188479f3c888f45e5ddcfe5c3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 13:14:16 +0200 Subject: [PATCH 196/264] [#346] nrepl: implement close and ls-sessions --- src/babashka/impl/nrepl_server.clj | 17 +++++++++- test/babashka/impl/nrepl_server_test.clj | 41 +++++++++++++++++++----- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index db62b227..58bd39c8 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -127,6 +127,15 @@ (send o (response-for msg {"completions" [] "status" #{"done"}}))))) +(defn close-session [ctx msg _is os id] + (swap! (:sessions ctx) disj id) + (send os (response-for msg {"status" #{"done" "session-closed"}}))) + +(defn ls-sessions [ctx msg os] + (let [sessions @(:sessions ctx)] + (send os (response-for msg {"sessions" sessions + "status" #{"done"}})))) + (defn read-msg [msg] (-> (zipmap (map keyword (keys msg)) (map #(if (bytes? %) @@ -145,6 +154,7 @@ :clone (do (when @dev? (println "Cloning!")) (let [id (str (java.util.UUID/randomUUID))] + (swap! (:sessions ctx) (fnil conj #{}) id) (send os (response-for msg {"new-session" id "status" #{"done"}})) (recur ctx is os id))) :eval (do @@ -162,6 +172,10 @@ "ops" (zipmap #{"clone" "eval" "load-file" "complete" "describe"} (repeat {}))})) (recur ctx is os id)) + :close (do (close-session ctx msg is os id) + (recur ctx is os id)) + :ls-sessions (do (ls-sessions ctx msg os) + (recur ctx is os id)) ;; fallback (do (when @dev? (println "Unhandled message" msg)) @@ -193,7 +207,8 @@ (defn start-server! [ctx host+port] (vreset! dev? (= "true" (System/getenv "BABASHKA_DEV"))) - (let [parts (str/split host+port #":") + (let [ctx (assoc ctx :sessions (atom #{})) + parts (str/split host+port #":") [address port] (if (= 1 (count parts)) [nil (Integer. ^String (first parts))] [(java.net.InetAddress/getByName (first parts)) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index 0892f9d7..b3412911 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -5,11 +5,12 @@ [babashka.main :as main] [babashka.test-utils :as tu] [babashka.wait :as wait] - [cheshire.core :as cheshire] [clojure.test :as t :refer [deftest is testing]] [sci.impl.opts :refer [init]]) (:import [java.lang ProcessBuilder$Redirect])) +(def debug? false) + (set! *warn-on-reflection* true) (defn bytes->str [x] @@ -24,6 +25,9 @@ (vals msg))) res (if-let [status (:status res)] (assoc res :status (mapv bytes->str status)) + res) + res (if-let [status (:sessions res)] + (assoc res :sessions (mapv bytes->str status)) res)] res)) @@ -32,8 +36,12 @@ (let [msg (read-msg (bencode/read-bencode in))] (if (and (= (:session msg) session) (= (:id msg) id)) - msg - (recur))))) + (do + (when debug? (prn "received" msg)) + msg) + (do + (when debug? (prn "skipping over msg" msg)) + (recur)))))) (defn nrepl-test [] (with-open [socket (java.net.Socket. "127.0.0.1" 1667) @@ -129,11 +137,28 @@ completions (mapv read-msg completions) completions (into #{} (map (juxt :ns :candidate)) completions)] (is (contains? completions ["clojure.test" "test/deftest"]))))) - #_(testing "interrupt" ;; .stop doesn't work on Thread in GraalVM, this is why we can't have this yet - (bencode/write-bencode os {"op" "eval" "code" "(range)" "session" session "id" 9}) - (Thread/sleep 1000) - (bencode/write-bencode os {"op" "interrupt" "session" session "interrupt-id" 9 "id" 10}) - (is (contains? (set (:status (read-reply in session 10))) "done")))))) + (testing "ls-sessions" + (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) + sessions (set (:sessions reply))] + (is (contains? sessions session)) + (bencode/write-bencode os {"op" "clone" "session" session "id" (new-id!)}) + (let [new-session (:new-session (read-reply in session @id))] + (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) + sessions (set (:sessions reply))] + (is (contains? sessions session)) + (is (contains? sessions new-session))) + (testing "close" + (bencode/write-bencode os {"op" "close" "session" new-session "id" (new-id!)}) + (let [reply (read-reply in new-session @id)] + (is (contains? (set (:status reply)) "session-closed")))) + (testing "session not listen in ls-sessions after close" + (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) + sessions (set (:sessions reply))] + (is (contains? sessions session)) + (is (not (contains? sessions new-session))))))))))) (deftest nrepl-server-test (let [proc-state (atom nil)] From f1c1a3db8ee8f4348eba45d7c46bc8a1c2f2d79c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 13:50:49 +0200 Subject: [PATCH 197/264] [#349] nrepl: write to output while evaluating --- src/babashka/impl/nrepl_server.clj | 38 +++----------- src/babashka/impl/nrepl_server/utils.clj | 63 ++++++++++++++++++++++++ test/babashka/impl/nrepl_server_test.clj | 8 ++- 3 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 src/babashka/impl/nrepl_server/utils.clj diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 58bd39c8..79fdcf51 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -1,7 +1,9 @@ (ns babashka.impl.nrepl-server {:no-doc true} (:refer-clojure :exclude [send future binding]) - (:require [babashka.impl.bencode.core :refer [write-bencode read-bencode]] + (:require [babashka.impl.bencode.core :refer [read-bencode]] + [babashka.impl.nrepl-server.utils :refer [dev? response-for send send-exception + replying-print-writer]] [clojure.string :as str] [clojure.tools.reader.reader-types :as r] [sci.core :as sci] @@ -9,35 +11,11 @@ [sci.impl.parser :as p] [sci.impl.utils :as sci-utils] [sci.impl.vars :as vars]) - (:import [java.io StringWriter OutputStream InputStream PushbackInputStream EOFException BufferedOutputStream] + (:import [java.io InputStream PushbackInputStream EOFException BufferedOutputStream] [java.net ServerSocket])) (set! *warn-on-reflection* true) -(def port 1667) -(def dev? (volatile! nil)) - -(defn response-for [old-msg msg] - (let [session (get old-msg :session "none") - id (get old-msg :id "unknown")] - (assoc msg "session" session "id" id))) - -(defn send [^OutputStream os msg] - ;;(when @dev? (prn "Sending" msg)) - (write-bencode os msg) - (.flush os)) - -(defn send-exception [os msg ^Throwable ex] - (let [ex-map (Throwable->map ex) - ex-name (-> ex-map :via first :type) - cause (:cause ex-map)] - (when @dev? (prn "sending exception" ex-map)) - (send os (response-for msg {"err" (str ex-name ": " cause "\n")})) - (send os (response-for msg {"ex" (str "class " ex-name) - "root-ex" (str "class " ex-name) - "status" #{"eval-error"}})) - (send os (response-for msg {"status" #{"done"}})))) - (defn eval-msg [ctx o msg] (try (let [code-str (get msg :code) @@ -48,12 +26,11 @@ (sci/with-bindings (cond-> {} sci-ns (assoc vars/current-ns sci-ns)) (loop [] - (let [sw (StringWriter.) + (let [pw (replying-print-writer o msg) form (p/parse-next ctx reader) value (if (identical? :edamame.impl.parser/eof form) ::nil - (sci/with-bindings {sci/out sw} + (sci/with-bindings {sci/out pw} (eval-form ctx form))) - out-str (not-empty (str sw)) env (:env ctx)] (swap! env update-in [:namespaces 'clojure.core] (fn [core] @@ -61,9 +38,6 @@ '*1 value '*2 (get core '*1) '*3 (get core '*2)))) - (when @dev? (println "out str:" out-str)) - (when out-str - (send o (response-for msg {"out" out-str}))) (send o (response-for msg (cond-> {"ns" (vars/current-ns-name)} (not (identical? value ::nil)) (assoc "value" (pr-str value))))) (when (not (identical? ::nil value)) diff --git a/src/babashka/impl/nrepl_server/utils.clj b/src/babashka/impl/nrepl_server/utils.clj new file mode 100644 index 00000000..46dca89f --- /dev/null +++ b/src/babashka/impl/nrepl_server/utils.clj @@ -0,0 +1,63 @@ +(ns babashka.impl.nrepl-server.utils + {:no-doc true} + (:refer-clojure :exclude [send]) + (:require [babashka.impl.bencode.core :refer [write-bencode]]) + (:import [java.io Writer PrintWriter StringWriter OutputStream BufferedWriter])) + +(set! *warn-on-reflection* true) + +(def dev? (volatile! nil)) + +(defn response-for [old-msg msg] + (let [session (get old-msg :session "none") + id (get old-msg :id "unknown")] + (assoc msg "session" session "id" id))) + +(defn send [^OutputStream os msg] + ;;(when @dev? (prn "Sending" msg)) + (write-bencode os msg) + (.flush os)) + +(defn send-exception [os msg ^Throwable ex] + (let [ex-map (Throwable->map ex) + ex-name (-> ex-map :via first :type) + cause (:cause ex-map)] + (when @dev? (prn "sending exception" ex-map)) + (send os (response-for msg {"err" (str ex-name ": " cause "\n")})) + (send os (response-for msg {"ex" (str "class " ex-name) + "root-ex" (str "class " ex-name) + "status" #{"eval-error"}})) + (send os (response-for msg {"status" #{"done"}})))) + +;; from https://github.com/nrepl/nrepl/blob/1cc9baae631703c184894559a2232275dc50dff6/src/clojure/nrepl/middleware/print.clj#L63 +(defn- to-char-array + ^chars + [x] + (cond + (string? x) (.toCharArray ^String x) + (integer? x) (char-array [(char x)]) + :else x)) + +;; from https://github.com/nrepl/nrepl/blob/1cc9baae631703c184894559a2232275dc50dff6/src/clojure/nrepl/middleware/print.clj#L99 +(defn replying-print-writer + "Returns a `java.io.PrintWriter` suitable for binding as `*out*` or `*err*`. All + of the content written to that `PrintWriter` will be sent as messages on the + transport of `msg`, keyed by `key`." + ^java.io.PrintWriter + [o msg] + (-> (proxy [Writer] [] + (write + ([x] + (let [cbuf (to-char-array x)] + (.write ^Writer this cbuf (int 0) (count cbuf)))) + ([x off len] + (let [cbuf (to-char-array x) + text (str (doto (StringWriter.) + (.write cbuf ^int off ^int len)))] + (when (pos? (count text)) + (when @dev? (println "out str:" text)) + (send o (response-for msg {"out" text})))))) + (flush []) + (close [])) + (BufferedWriter. 1024) + (PrintWriter. true))) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index b3412911..f7215003 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -158,7 +158,13 @@ (let [reply (read-reply in session @id) sessions (set (:sessions reply))] (is (contains? sessions session)) - (is (not (contains? sessions new-session))))))))))) + (is (not (contains? sessions new-session)))))))) + (testing "output" + (bencode/write-bencode os {"op" "eval" "code" "(dotimes [i 3] (println \"Hello\"))" + "session" session "id" (new-id!)}) + (dotimes [_ 3] + (let [reply (read-reply in session @id)] + (is (= "Hello\n" (:out reply))))))))) (deftest nrepl-server-test (let [proc-state (atom nil)] From 4318fc01927cb6841f35f9479a8a99d622803036 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 14:25:36 +0200 Subject: [PATCH 198/264] [#346] nrepl: fix close --- src/babashka/impl/nrepl_server.clj | 7 +++-- test/babashka/impl/nrepl_server_test.clj | 36 +++++++++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index 79fdcf51..e9bf05b7 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -101,8 +101,9 @@ (send o (response-for msg {"completions" [] "status" #{"done"}}))))) -(defn close-session [ctx msg _is os id] - (swap! (:sessions ctx) disj id) +(defn close-session [ctx msg _is os] + (let [session (:session msg)] + (swap! (:sessions ctx) disj session)) (send os (response-for msg {"status" #{"done" "session-closed"}}))) (defn ls-sessions [ctx msg os] @@ -146,7 +147,7 @@ "ops" (zipmap #{"clone" "eval" "load-file" "complete" "describe"} (repeat {}))})) (recur ctx is os id)) - :close (do (close-session ctx msg is os id) + :close (do (close-session ctx msg is os) (recur ctx is os id)) :ls-sessions (do (ls-sessions ctx msg os) (recur ctx is os id)) diff --git a/test/babashka/impl/nrepl_server_test.clj b/test/babashka/impl/nrepl_server_test.clj index f7215003..52613754 100644 --- a/test/babashka/impl/nrepl_server_test.clj +++ b/test/babashka/impl/nrepl_server_test.clj @@ -137,28 +137,36 @@ completions (mapv read-msg completions) completions (into #{} (map (juxt :ns :candidate)) completions)] (is (contains? completions ["clojure.test" "test/deftest"]))))) - (testing "ls-sessions" + (testing "close + ls-sessions" (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) (let [reply (read-reply in session @id) sessions (set (:sessions reply))] (is (contains? sessions session)) - (bencode/write-bencode os {"op" "clone" "session" session "id" (new-id!)}) - (let [new-session (:new-session (read-reply in session @id))] + (let [new-sessions (loop [i 0 + sessions #{}] + (bencode/write-bencode os {"op" "clone" "session" session "id" (new-id!)}) + (let [new-session (:new-session (read-reply in session @id)) + sessions (conj sessions new-session)] + (if (= i 4) + sessions + (recur (inc i) sessions))))] (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) (let [reply (read-reply in session @id) sessions (set (:sessions reply))] + (is (= 6 (count sessions))) (is (contains? sessions session)) - (is (contains? sessions new-session))) - (testing "close" - (bencode/write-bencode os {"op" "close" "session" new-session "id" (new-id!)}) - (let [reply (read-reply in new-session @id)] - (is (contains? (set (:status reply)) "session-closed")))) - (testing "session not listen in ls-sessions after close" - (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) - (let [reply (read-reply in session @id) - sessions (set (:sessions reply))] - (is (contains? sessions session)) - (is (not (contains? sessions new-session)))))))) + (is (= new-sessions (disj sessions session))) + (testing "close" + (doseq [close-session (disj sessions session)] + (bencode/write-bencode os {"op" "close" "session" close-session "id" (new-id!)}) + (let [reply (read-reply in close-session @id)] + (is (contains? (set (:status reply)) "session-closed"))))) + (testing "session not listen in ls-sessions after close" + (bencode/write-bencode os {"op" "ls-sessions" "session" session "id" (new-id!)}) + (let [reply (read-reply in session @id) + sessions (set (:sessions reply))] + (is (contains? sessions session)) + (is (not (some #(contains? sessions %) new-sessions))))))))) (testing "output" (bencode/write-bencode os {"op" "eval" "code" "(dotimes [i 3] (println \"Hello\"))" "session" session "id" (new-id!)}) From cca63e913f415257cb8054f91adf9bc6ac0e7773 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:30:39 +0200 Subject: [PATCH 199/264] [#344] add nREPL docs --- README.md | 50 +------------ doc/repl.md | 111 +++++++++++++++++++++++++++++ src/babashka/impl/nrepl_server.clj | 7 +- 3 files changed, 116 insertions(+), 52 deletions(-) create mode 100644 doc/repl.md diff --git a/README.md b/README.md index d2b63c36..d57d72f7 100644 --- a/README.md +++ b/README.md @@ -653,55 +653,7 @@ bb -cp "src:test:resources" \ (System/exit (+ fail error)))" ``` -## REPL - -Babashka supports both a REPL and socket REPL. To start the REPL, type: - -``` shell -$ bb --repl -``` - -To get history with up and down arrows, use `rlwrap`: - -``` shell -$ rlwrap bb --repl -``` - -To start the socket REPL you can do this: - -``` shellsession -$ bb --socket-repl 1666 -Babashka socket REPL started at localhost:1666 -``` - -Now you can connect with your favorite socket REPL client: - -``` shellsession -$ rlwrap nc 127.0.0.1 1666 -Babashka v0.0.14 REPL. -Use :repl/quit or :repl/exit to quit the REPL. -Clojure rocks, Bash reaches. - -bb=> (+ 1 2 3) -6 -bb=> :repl/quit -$ -``` - -Editor plugins offering auto-completion support when connected to a babashka socket REPL: - -- Emacs: [inf-clojure](https://github.com/clojure-emacs/inf-clojure): - - To connect: - - `M-x inf-clojure-connect localhost 1666` - - Before evaluating from a Clojure buffer: - - `M-x inf-clojure-minor-mode` - -- Atom: [chlorine](https://github.com/mauricioszabo/atom-chlorine) -- Vim: [vim-iced](https://github.com/liquidz/vim-iced) +## [REPL](doc/repl.md) ## Spawning and killing a process diff --git a/doc/repl.md b/doc/repl.md new file mode 100644 index 00000000..0bf5b047 --- /dev/null +++ b/doc/repl.md @@ -0,0 +1,111 @@ +# REPLs + +Babashka supports running a REPL, a socket REPL and an nREPL server. + +## REPL + +To start the REPL, type: + +``` shell +$ bb --repl +``` + +To get history with up and down arrows, use `rlwrap`: + +``` shell +$ rlwrap bb --repl +``` + +## Socket REPL + +To start the socket REPL you can do this: + +``` shellsession +$ bb --socket-repl 1666 +Babashka socket REPL started at localhost:1666 +``` + +Now you can connect with your favorite socket REPL client: + +``` shellsession +$ rlwrap nc 127.0.0.1 1666 +Babashka v0.0.14 REPL. +Use :repl/quit or :repl/exit to quit the REPL. +Clojure rocks, Bash reaches. + +bb=> (+ 1 2 3) +6 +bb=> :repl/quit +$ +``` + +Editor plugins known to work with a babashka socket REPL: + +- Emacs: [inf-clojure](https://github.com/clojure-emacs/inf-clojure): + + To connect: + + `M-x inf-clojure-connect localhost 1666` + + Before evaluating from a Clojure buffer: + + `M-x inf-clojure-minor-mode` + +- Atom: [Chlorine](https://github.com/mauricioszabo/atom-chlorine) +- Vim: [vim-iced](https://github.com/liquidz/vim-iced) +- IntelliJ IDEA: [Cursive](https://cursive-ide.com/) + + Note: you will have to use a workaround via + [tubular](https://github.com/mfikes/tubular). For more info, look + [here](https://cursive-ide.com/userguide/repl.html#repl-types). + + +## nREPL + +To start an nREPL server: + +``` shell +$ bb --nrepl-server 1667 +``` + +Then connect with your favorite nREPL client: + +``` shell +$ lein repl :connect 1667 +Connecting to nREPL at 127.0.0.1:1667 +user=> (+ 1 2 3) +6 +user=> +``` + +Editor plugins known to work with the babashka nREPL server: + + - Emacs: [CIDER](https://docs.cider.mx/cider-nrepl/) + - `lein repl :connect` + - VSCode: [Calva](http://calva.io/) + - Atom: [Chlorine](https://github.com/mauricioszabo/atom-chlorine) + - (Neo)Vim: [vim-iced](https://github.com/liquidz/vim-iced), [conjure](https://github.com/Olical/conjure), [fireplace](https://github.com/tpope/vim-fireplace) + +The babashka nREPL server does not write an `.nrepl-port` file at startup, but +you can easily write a script that launches the server and write the file +yourself: + + ``` clojure + #!/usr/bin/env bb + +(import [java.net ServerSocket] + [java.io File] + [java.lang ProcessBuilder$Redirect]) + +(require '[babashka.wait :as wait]) + +(let [nrepl-port (with-open [sock (ServerSocket. 0)] (.getLocalPort sock)) + pb (doto (ProcessBuilder. (into ["bb" "--nrepl-server" (str nrepl-port)] + *command-line-args*)) + (.redirectOutput ProcessBuilder$Redirect/INHERIT)) + proc (.start pb)] + (wait/wait-for-port "localhost" nrepl-port) + (spit ".nrepl-port" nrepl-port) + (.deleteOnExit (File. ".nrepl-port")) + (.waitFor proc)) + ``` diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index e9bf05b7..b4601623 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -132,6 +132,8 @@ (swap! (:sessions ctx) (fnil conj #{}) id) (send os (response-for msg {"new-session" id "status" #{"done"}})) (recur ctx is os id))) + :close (do (close-session ctx msg is os) + (recur ctx is os id)) :eval (do (eval-msg ctx os msg) (recur ctx is os id)) @@ -144,11 +146,10 @@ (recur ctx is os id)) :describe (do (send os (response-for msg {"status" #{"done"} - "ops" (zipmap #{"clone" "eval" "load-file" "complete" "describe"} + "ops" (zipmap #{"clone" "close" "eval" "load-file" + "complete" "describe" "ls-sessions"} (repeat {}))})) (recur ctx is os id)) - :close (do (close-session ctx msg is os) - (recur ctx is os id)) :ls-sessions (do (ls-sessions ctx msg os) (recur ctx is os id)) ;; fallback From 658f115bfbece0d2d4721a20ad9b844f61cae8c1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:33:20 +0200 Subject: [PATCH 200/264] [#344] add nREPL docs --- README.md | 7 +++++-- doc/repl.md | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d57d72f7..635289bd 100644 --- a/README.md +++ b/README.md @@ -415,6 +415,11 @@ $ cat script.clj ("hello" "1" "2" "3") ``` +## [Running a REPL](doc/repl.md) + +Babashka offers a REPL, a socket REPL and an nREPL server. Look +[here](doc/repl.md) for more information. + ## Preloads The environment variable `BABASHKA_PRELOADS` allows to define code that will be @@ -653,8 +658,6 @@ bb -cp "src:test:resources" \ (System/exit (+ fail error)))" ``` -## [REPL](doc/repl.md) - ## Spawning and killing a process Use the `java.lang.ProcessBuilder` class. diff --git a/doc/repl.md b/doc/repl.md index 0bf5b047..a0c8bd1a 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -1,4 +1,4 @@ -# REPLs +# Running a REPL Babashka supports running a REPL, a socket REPL and an nREPL server. From 4dd008434b4c2cda89bee4b4163585b8082a6ac7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:34:54 +0200 Subject: [PATCH 201/264] [#344] add nREPL docs --- doc/repl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/repl.md b/doc/repl.md index a0c8bd1a..26d211bc 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -20,14 +20,14 @@ $ rlwrap bb --repl To start the socket REPL you can do this: -``` shellsession +``` shell $ bb --socket-repl 1666 Babashka socket REPL started at localhost:1666 ``` Now you can connect with your favorite socket REPL client: -``` shellsession +``` shell $ rlwrap nc 127.0.0.1 1666 Babashka v0.0.14 REPL. Use :repl/quit or :repl/exit to quit the REPL. From ddb2498664a100831cdc26969bac2d07ca5f9c48 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:36:47 +0200 Subject: [PATCH 202/264] [#344] add nREPL docs --- doc/repl.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/repl.md b/doc/repl.md index 26d211bc..b2ccca86 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -109,3 +109,21 @@ yourself: (.deleteOnExit (File. ".nrepl-port")) (.waitFor proc)) ``` + +### Debugging the nREPL server + +To debug the nREPL server from the binary you can run: + +``` shell +$ BABASHKA_DEV=true bb --nrepl-server 1667 +``` + +This will print all the incoming messages. + +To debug the nREPL server from source: + +``` clojure +$ git clone https://github.com/borkdude/babashka --recursive +$ cd babashka +$ BABASHKA_DEV=true clojure -A:main --nrepl-server 1667 +``` From eaf8da5853a617de1516fc3003176c4e331e6f07 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:37:28 +0200 Subject: [PATCH 203/264] [#344] add nREPL docs --- doc/repl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/repl.md b/doc/repl.md index b2ccca86..e051c242 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -70,7 +70,7 @@ $ bb --nrepl-server 1667 Then connect with your favorite nREPL client: -``` shell +``` clojure $ lein repl :connect 1667 Connecting to nREPL at 127.0.0.1:1667 user=> (+ 1 2 3) From 8266349df8f11c954b6189ac25856d6d15ccda47 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:41:48 +0200 Subject: [PATCH 204/264] [#344] print link to nREPL docs --- src/babashka/impl/nrepl_server.clj | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/babashka/impl/nrepl_server.clj b/src/babashka/impl/nrepl_server.clj index b4601623..7e1fbf4d 100644 --- a/src/babashka/impl/nrepl_server.clj +++ b/src/babashka/impl/nrepl_server.clj @@ -190,8 +190,9 @@ [(java.net.InetAddress/getByName (first parts)) (Integer. ^String (second parts))]) host+port (if-not address (str "localhost:" port) - host+port)] - (println "Starting nREPL server at" host+port) - (let [socket-server (new ServerSocket port 0 address)] - (reset! server socket-server) - (listen ctx socket-server)))) + host+port) + socket-server (new ServerSocket port 0 address)] + (println "Started nREPL server at" host+port) + (println "For more info visit https://github.com/borkdude/babashka/blob/master/doc/repl.md#nrepl.") + (reset! server socket-server) + (listen ctx socket-server))) From 553115c56a1c61a56c2850ae8145c44fdc32816c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:49:44 +0200 Subject: [PATCH 205/264] v0.0.83 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index aa5b4be9..4d2aab68 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.83-SNAPSHOT \ No newline at end of file +0.0.83 \ No newline at end of file From 79ac081161d472d9c4f6222394f0935892659368 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 16:59:13 +0200 Subject: [PATCH 206/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 85013834..4d2aab68 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.82 \ No newline at end of file +0.0.83 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 4d2aab68..7b1a7952 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.83 \ No newline at end of file +0.0.84-SNAPSHOT \ No newline at end of file From 0657cfd13f89dbde658cedf60d356f28be398f33 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 17:04:33 +0200 Subject: [PATCH 207/264] doc --- doc/repl.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/repl.md b/doc/repl.md index e051c242..e48c3072 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -87,8 +87,7 @@ Editor plugins known to work with the babashka nREPL server: - (Neo)Vim: [vim-iced](https://github.com/liquidz/vim-iced), [conjure](https://github.com/Olical/conjure), [fireplace](https://github.com/tpope/vim-fireplace) The babashka nREPL server does not write an `.nrepl-port` file at startup, but -you can easily write a script that launches the server and write the file -yourself: +you can easily write a script that launches the server and writes the file: ``` clojure #!/usr/bin/env bb From 71c3f9ad5ccedbab23ea16f5940a2d4e8a5eae58 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 17:05:17 +0200 Subject: [PATCH 208/264] doc --- doc/repl.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/repl.md b/doc/repl.md index e48c3072..6fbc35ac 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -89,8 +89,8 @@ Editor plugins known to work with the babashka nREPL server: The babashka nREPL server does not write an `.nrepl-port` file at startup, but you can easily write a script that launches the server and writes the file: - ``` clojure - #!/usr/bin/env bb +``` clojure +#!/usr/bin/env bb (import [java.net ServerSocket] [java.io File] @@ -107,7 +107,7 @@ you can easily write a script that launches the server and writes the file: (spit ".nrepl-port" nrepl-port) (.deleteOnExit (File. ".nrepl-port")) (.waitFor proc)) - ``` +``` ### Debugging the nREPL server From fe0aec3bee2671c5eb0abdde24337e17c721ed02 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 17:13:09 +0200 Subject: [PATCH 209/264] doc --- doc/repl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/repl.md b/doc/repl.md index 6fbc35ac..2cdb836e 100644 --- a/doc/repl.md +++ b/doc/repl.md @@ -39,7 +39,7 @@ bb=> :repl/quit $ ``` -Editor plugins known to work with a babashka socket REPL: +Editor plugins and tools known to work with a babashka socket REPL: - Emacs: [inf-clojure](https://github.com/clojure-emacs/inf-clojure): @@ -78,7 +78,7 @@ user=> (+ 1 2 3) user=> ``` -Editor plugins known to work with the babashka nREPL server: +Editor plugins and tools known to work with the babashka nREPL server: - Emacs: [CIDER](https://docs.cider.mx/cider-nrepl/) - `lein repl :connect` From af1c8fd4d8a7683df0dd35e69857d695ed8b03b0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 17:30:26 +0200 Subject: [PATCH 210/264] Bump sci version --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 7ac60d81..b5979e4c 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 7ac60d818d97895d275fdd58a4cc677515d26f74 +Subproject commit b5979e4c268311303df600eb5520af688f1cb874 From ed4fb6cd3457d536be64c5cdd45ec7c7a7dfa033 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 20:47:31 +0200 Subject: [PATCH 211/264] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 635289bd..3c4a076e 100644 --- a/README.md +++ b/README.md @@ -1156,7 +1156,7 @@ clojure.core/ffirst (defn sha1 [s] - (let [hashed (.digest (.getInstance java.security.MessageDigest "SHA-1") + (let [hashed (.digest (java.security.MessageDigest/getInstance "SHA-1") (.getBytes s)) sw (java.io.StringWriter.)] (binding [*out* sw] From 61b7cb8321a76c519bf43811a1984a328ccc82f9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 21:13:33 +0200 Subject: [PATCH 212/264] Add which example --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 3c4a076e..c367fb61 100644 --- a/README.md +++ b/README.md @@ -1222,6 +1222,15 @@ example. If you get prompted with a login, use `admin`/`admin`. +### which + +The `which` command re-implemented in Clojure. Prints the canonical file name. + +``` shell +$ examples/which.clj rg +/usr/local/Cellar/ripgrep/11.0.1/bin/rg +``` + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support From 3bf9ccd530dfb0e835d4cc584ef1e6d3979dac49 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 21:13:47 +0200 Subject: [PATCH 213/264] Add which example --- examples/which.clj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 examples/which.clj diff --git a/examples/which.clj b/examples/which.clj new file mode 100755 index 00000000..fbd9666c --- /dev/null +++ b/examples/which.clj @@ -0,0 +1,17 @@ +#!/usr/bin/env bb + +(require '[clojure.java.io :as io]) + +(defn where [executable] + (let [path (System/getenv "PATH") + paths (.split path (System/getProperty "path.separator"))] + (loop [paths paths] + (when-first [p paths] + (let [f (io/file p executable)] + (if (and (.isFile f) + (.canExecute f)) + (.getCanonicalPath f) + (recur (rest paths)))))))) + +(when-let [executable (first *command-line-args*)] + (println (where executable))) From 20b1c5630055099d9284914e2bbf78ed380f0e2f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 21:16:30 +0200 Subject: [PATCH 214/264] doc --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c367fb61..dc1a35c9 100644 --- a/README.md +++ b/README.md @@ -1224,7 +1224,11 @@ example. If you get prompted with a login, use `admin`/`admin`. ### which -The `which` command re-implemented in Clojure. Prints the canonical file name. +The `which` command re-implemented in Clojure. + +See +[examples/which.clj](https://github.com/borkdude/babashka/blob/master/examples/which.clj). +Prints the canonical file name. ``` shell $ examples/which.clj rg From 865f724f56dc73517936eef53876e47d784326f5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 21:16:53 +0200 Subject: [PATCH 215/264] doc --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index dc1a35c9..a54ff273 100644 --- a/README.md +++ b/README.md @@ -1224,9 +1224,7 @@ example. If you get prompted with a login, use `admin`/`admin`. ### which -The `which` command re-implemented in Clojure. - -See +The `which` command re-implemented in Clojure. See [examples/which.clj](https://github.com/borkdude/babashka/blob/master/examples/which.clj). Prints the canonical file name. From db2281659c267ccdac4c4463c383698124dc9eac Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 12 Apr 2020 21:19:22 +0200 Subject: [PATCH 216/264] doc --- examples/which.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/which.clj b/examples/which.clj index fbd9666c..8bc43cee 100755 --- a/examples/which.clj +++ b/examples/which.clj @@ -2,7 +2,7 @@ (require '[clojure.java.io :as io]) -(defn where [executable] +(defn which [executable] (let [path (System/getenv "PATH") paths (.split path (System/getProperty "path.separator"))] (loop [paths paths] @@ -14,4 +14,4 @@ (recur (rest paths)))))))) (when-let [executable (first *command-line-args*)] - (println (where executable))) + (println (which executable))) From e80fc1dee91805d175413029ccddcb0686efd41e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 15:25:21 +0200 Subject: [PATCH 217/264] [#318] support :refer :all --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index b5979e4c..ed49cc7e 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit b5979e4c268311303df600eb5520af688f1cb874 +Subproject commit ed49cc7ee1743c02625e08196b449a06d27b5ae5 From 3c2e17844d310aab9695a1ca22023f642b233323 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 16:49:28 +0200 Subject: [PATCH 218/264] [#353] set babashka.main property --- src/babashka/main.clj | 1 + .../babashka/src_for_classpath_test/my/main2.clj | 4 ++++ test/babashka/classpath_test.clj | 8 ++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 test-resources/babashka/src_for_classpath_test/my/main2.clj diff --git a/src/babashka/main.clj b/src/babashka/main.clj index caa3ebdd..d183a1bb 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -318,6 +318,7 @@ Everything after that is bound to *command-line-args*.")) :verbose? :classpath :main :uberscript] :as _opts} (parse-opts args) + _ (when main (System/setProperty "babashka.main" main)) read-next (fn [*in*] (if (pipe-signal-received?) ::EOF diff --git a/test-resources/babashka/src_for_classpath_test/my/main2.clj b/test-resources/babashka/src_for_classpath_test/my/main2.clj new file mode 100644 index 00000000..49a3c7f3 --- /dev/null +++ b/test-resources/babashka/src_for_classpath_test/my/main2.clj @@ -0,0 +1,4 @@ +(ns my.main2) + +(defn -main [& _args] + (System/getProperty "babashka.main")) diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj index 733cf2e0..c03ade13 100644 --- a/test/babashka/classpath_test.clj +++ b/test/babashka/classpath_test.clj @@ -3,7 +3,8 @@ [babashka.test-utils :as tu] [clojure.edn :as edn] [clojure.java.io :as io] - [clojure.test :as t :refer [deftest is]])) + [clojure.test :as t :refer [deftest is testing]] + [clojure.string :as str])) (defn bb [input & args] (edn/read-string (apply tu/bb (when (some? input) (str input)) (map str args)))) @@ -28,7 +29,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 "--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")))))) (deftest uberscript-test (let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")] From cc7da5c4957a62f89a7d0286eab8ad5f54081610 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 17:20:39 +0200 Subject: [PATCH 219/264] borkdude/sci#303 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index ed49cc7e..89e89554 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit ed49cc7ee1743c02625e08196b449a06d27b5ae5 +Subproject commit 89e8955480893362a44a4c8af385c56570e6a007 From b7d8edf23e1a7b71eb8922683711dd0d7502cde9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 18:11:03 +0200 Subject: [PATCH 220/264] borkdude/sci#303 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 89e89554..ac733d1e 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 89e8955480893362a44a4c8af385c56570e6a007 +Subproject commit ac733d1efca4d3f793bb5ba7d7ac701ead7e78a8 From 6d80a412e97a87269a9f64adc5538aa086fc53ff Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 20:36:26 +0200 Subject: [PATCH 221/264] [#317] add clojure.repl/find-doc --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index ac733d1e..b425eede 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit ac733d1efca4d3f793bb5ba7d7ac701ead7e78a8 +Subproject commit b425eedeebd8612d42befa92b800a25c824b8c49 From 88ab267604fd580d3fe4052db3fa6f6749bb7cbf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 20:37:07 +0200 Subject: [PATCH 222/264] v0.0.84 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 7b1a7952..50a03442 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.84-SNAPSHOT \ No newline at end of file +0.0.84 \ No newline at end of file From d07522723c6e7780398a84573410cecfec0efcf4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 20:50:32 +0200 Subject: [PATCH 223/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 4d2aab68..50a03442 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.83 \ No newline at end of file +0.0.84 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 50a03442..1cb12897 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.84 \ No newline at end of file +0.0.85-SNAPSHOT \ No newline at end of file From da8714805e352c41a232b0bb64d80a047ec0cfc3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 21:16:13 +0200 Subject: [PATCH 224/264] doc --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a54ff273..182a06ae 100644 --- a/README.md +++ b/README.md @@ -508,6 +508,9 @@ $ bb "(my-gist-script/-main)" Hello from gist script! ``` +When invoking `bb` with a main function the expression `(System/getProperty +"babashka.main")` will return the name of the main function. + Also see the [babashka.classpath](https://github.com/borkdude/babashka/#babashkaclasspath) namespace which allows dynamically adding to the classpath. From cda52fd3647264c603703cafc67a0720ff6e881a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 21:16:55 +0200 Subject: [PATCH 225/264] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 182a06ae..52eb0127 100644 --- a/README.md +++ b/README.md @@ -508,7 +508,7 @@ $ bb "(my-gist-script/-main)" Hello from gist script! ``` -When invoking `bb` with a main function the expression `(System/getProperty +When invoking `bb` with a main function, the expression `(System/getProperty "babashka.main")` will return the name of the main function. Also see the From 475b1a9807fee17ecb30c1b543e596fdccff0658 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 21:48:40 +0200 Subject: [PATCH 226/264] doc --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 52eb0127..0c6a8b15 100644 --- a/README.md +++ b/README.md @@ -781,7 +781,7 @@ Differences with Clojure: than in Clojure on the JVM. In general interpretation yields slower programs than compiled programs. -- No support for unboxed types. +- No `defprotocol`, `defrecord` and unboxed math. ## External resources @@ -942,6 +942,10 @@ babashka. A collection of scripts developed by [https://github.com/justone](@justone). +#### [nativity](https://github.com/MnRA/nativity) + +Turn babashka scripts into binaries using GraalVM `native-image`. + ## Package babashka script as a AWS Lambda AWS Lambda runtime doesn't support signals, therefore babashka has to disable From da05097d93d02f04e69cf415bfab574464011050 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 21:49:27 +0200 Subject: [PATCH 227/264] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c6a8b15..2584cca6 100644 --- a/README.md +++ b/README.md @@ -940,7 +940,7 @@ babashka. #### [justone/bb-scripts](https://github.com/justone/bb-scripts) -A collection of scripts developed by [https://github.com/justone](@justone). +A collection of scripts developed by [@justone](https://github.com/justone). #### [nativity](https://github.com/MnRA/nativity) From 3ec5e1806d733efbf8c090c08a8143d451e5d334 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 13 Apr 2020 21:57:21 +0200 Subject: [PATCH 228/264] Use clojure.repl at REPL startup --- src/babashka/impl/repl.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index c60b6cf9..e98ffce3 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -35,7 +35,7 @@ (sio/println "Use :repl/quit or :repl/exit to quit the REPL.") (sio/println "Clojure rocks, Bash reaches.") (sio/println) - (eval-form sci-ctx '(require '[clojure.repl :refer [dir doc]])))) + (eval-form sci-ctx '(use 'clojure.repl)))) :read (or read (fn [_request-prompt request-exit] ;; (prn "PEEK" @sci/in (r/peek-char @sci/in)) From ffcbfa02b81173550ddf4869944846f5f4e77d05 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 13:12:33 +0200 Subject: [PATCH 229/264] [#351] exit REPL on ctrl-D --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- src/babashka/impl/repl.clj | 16 ++++++---------- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/deps.edn b/deps.edn index 61c36244..15f1651e 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {:paths ["src" "sci/src" "babashka.curl/src" "resources" "sci/resources"], :deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}, org.clojure/tools.reader {:mvn/version "1.3.2"}, - borkdude/edamame {:mvn/version "0.0.11-alpha.6"}, + borkdude/edamame {:mvn/version "0.0.11-alpha.8"}, borkdude/graal.locking {:mvn/version "0.0.2"}, borkdude/sci.impl.reflector {:mvn/version "0.0.1"} org.clojure/core.async {:mvn/version "1.0.567"}, diff --git a/project.clj b/project.clj index de221f34..43676d95 100644 --- a/project.clj +++ b/project.clj @@ -13,7 +13,7 @@ :resource-paths ["resources" "sci/resources"] :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] - [borkdude/edamame "0.0.11-alpha.6"] + [borkdude/edamame "0.0.11-alpha.8"] [borkdude/graal.locking "0.0.2"] [borkdude/sci.impl.reflector "0.0.1"] [org.clojure/core.async "1.0.567"] diff --git a/sci b/sci index b425eede..22bd9221 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit b425eedeebd8612d42befa92b800a25c824b8c49 +Subproject commit 22bd92211c82b885b079b94d175eb821edb2e9b4 diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index e98ffce3..9e2674c8 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -38,16 +38,12 @@ (eval-form sci-ctx '(use 'clojure.repl)))) :read (or read (fn [_request-prompt request-exit] - ;; (prn "PEEK" @sci/in (r/peek-char @sci/in)) - ;; (prn "PEEK" @sci/in (r/peek-char @sci/in)) this works fine - (if (r/peek-char in) ;; if this is nil, we reached EOF - (let [v (parser/parse-next sci-ctx in)] - (if (or (identical? :repl/quit v) - (identical? :repl/exit v) - (identical? :edamame.impl.parser/eof v)) - request-exit - v)) - request-exit))) + (let [v (parser/parse-next sci-ctx in)] + (if (or (identical? :repl/quit v) + (identical? :repl/exit v) + (identical? :edamame.impl.parser/eof v)) + request-exit + v)))) :eval (or eval (fn [expr] (let [ret (eval-form (update sci-ctx From 36c163a4449e43cc99be2ce5b32794d854d4ab68 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 18:02:38 +0200 Subject: [PATCH 230/264] Add java.lang.Comparable --- src/babashka/impl/classes.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index aa97b177..487345d6 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -33,6 +33,7 @@ java.lang.AssertionError java.lang.Boolean java.lang.Byte + java.lang.Comparable java.lang.Class java.lang.Double java.lang.Exception From c3ee37e8c1d881bab7ca8d91cb1f70b4ce4797be Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:08:37 +0200 Subject: [PATCH 231/264] Add classes for statsd client --- src/babashka/impl/classes.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 487345d6..88361a8b 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -53,11 +53,14 @@ java.lang.ProcessBuilder java.lang.ProcessBuilder$Redirect java.math.BigInteger - java.net.URI + java.net.DatagramSocket + java.net.DatagramPacket java.net.HttpURLConnection + java.net.InetAddress java.net.ServerSocket java.net.Socket java.net.UnknownHostException + java.net.URI java.net.URLEncoder java.net.URLDecoder java.nio.file.CopyOption From cd13e4420d4922ef650e9eeecf9816c11d191fb9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:17:20 +0200 Subject: [PATCH 232/264] Add statsd test --- test/babashka/main_test.clj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index fa58881f..057f8b81 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -402,6 +402,13 @@ (bb nil (format "(.deleteOnExit (io/file \"%s\"))" p)) (is (false? (.exists f)))))) +(deftest statsd-client-test + (is (= :success (bb nil " +(load-file (io/file \"test-resources\" \"babashka\" \"statsd.clj\")) +(require '[statsd-client :as c]) +(c/increment :foo) +:success")))) + ;;;; Scratch (comment From 31c9481fda0a42f6eb1e60dd37da56bd7ab96f77 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:17:36 +0200 Subject: [PATCH 233/264] Add statsd test --- test-resources/babashka/statsd.clj | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 test-resources/babashka/statsd.clj diff --git a/test-resources/babashka/statsd.clj b/test-resources/babashka/statsd.clj new file mode 100644 index 00000000..959fc3bf --- /dev/null +++ b/test-resources/babashka/statsd.clj @@ -0,0 +1,49 @@ +(ns statsd-client + "a simple StatsD client written in Clojure + + Usage: + statsd-client/increment 'foo + statsd-client/decrement 'foo + statsd-client/increment 'foo 1 + statsd-client/decrement 'foo 1 + statsd-client/gauge 'foo 1 + statsd-client/timing 'foo 1 + " + (:import (java.net InetAddress DatagramPacket DatagramSocket))) + +(def server-address "127.0.0.1") +(def server-port 8125) + +; UDP helper functions +(defn make-socket + ([] (new DatagramSocket)) + ([port] (new DatagramSocket port))) + +(defn send-data [send-socket ip port data] + (let [ipaddress (InetAddress/getByName ip), + send-packet (new DatagramPacket (.getBytes data) (.length data) ipaddress port)] + (.send send-socket send-packet))) + +(defn make-send [ip port] + (let [send-socket (make-socket)] + (fn [data] (send-data send-socket ip port data)))) + +(def send-msg (make-send server-address server-port)) + +; statsd client functions +(defn increment + ([metric] (increment metric 1)) + ([metric value] + (send-msg (str metric ":" value "|c")))) + +(defn decrement + ([metric] (increment metric -1)) + ([metric value] + (send-msg (str metric ":" value "|c")))) + +(defn timing [metric value] + (send-msg (str metric ":" value "|ms"))) + +(defn gauge [metric value] + (send-msg (str metric ":" value "|g"))) + From a62379044372e06a34f6ae4fb7dc043abd7739e8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:24:39 +0200 Subject: [PATCH 234/264] [#355] Add test for arrangement library --- README.md | 5 +++++ script/run_lib_tests | 1 + 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 2584cca6..03c8065e 100644 --- a/README.md +++ b/README.md @@ -946,6 +946,11 @@ A collection of scripts developed by [@justone](https://github.com/justone). Turn babashka scripts into binaries using GraalVM `native-image`. +#### [arrangement](https://github.com/greglook/clj-arrangement) + +A micro-library which provides a total-ordering comparator for Clojure +values. Tested with version `1.2.0`. + ## Package babashka script as a AWS Lambda AWS Lambda runtime doesn't support signals, therefore babashka has to disable diff --git a/script/run_lib_tests b/script/run_lib_tests index aaa56bf3..3130036b 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -11,3 +11,4 @@ script/lib_tests/medley_test script/lib_tests/babashka_curl_test script/lib_tests/cprop_test script/lib_tests/comb_test +script/lib_tests/arrangement_test From a8b7059ccc591f764728f0d63b332d56d2993d29 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:24:46 +0200 Subject: [PATCH 235/264] [#355] Add test for arrangement library --- script/lib_tests/arrangement_test | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 script/lib_tests/arrangement_test diff --git a/script/lib_tests/arrangement_test b/script/lib_tests/arrangement_test new file mode 100755 index 00000000..fa93438f --- /dev/null +++ b/script/lib_tests/arrangement_test @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -eo pipefail + +export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {mvxcvi/arrangement {:mvn/version "1.2.0"}}}' -Spath) + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + +$BB_CMD -e "(require '[arrangement.core :as order]) (sort order/rank ['a false 2 :b nil 3.14159 \"c\" true \d [3 2] #{:one :two} [3 1 2] #{:three}])" From a9c50b1a39abfed6f850c2df867c88333bd359c2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 14 Apr 2020 22:54:31 +0200 Subject: [PATCH 236/264] Comment --- src/babashka/impl/classes.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 88361a8b..21a74071 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -61,6 +61,7 @@ java.net.Socket java.net.UnknownHostException java.net.URI + ;; java.net.URL, see below java.net.URLEncoder java.net.URLDecoder java.nio.file.CopyOption From c9c359e251642ef410330c93e2ad6adbdb57df7d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 12:09:57 +0200 Subject: [PATCH 237/264] borkdude/babashka.curl#4 --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 4b77c8c5..b6ad0648 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 4b77c8c5a31eefb46d4977d356f9cfa5546db6a6 +Subproject commit b6ad0648d8e59220924ea196e1ebac50cf6af503 From 5f914cedd1eaa0bc8bddbd3e0cde02cb412ddd05 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 12:22:08 +0200 Subject: [PATCH 238/264] [#263] add yaml library --- README.md | 3 ++- deps.edn | 5 ++--- doc/dev.md | 3 +++ project.clj | 4 ++-- src/babashka/impl/yaml.clj | 11 +++++++++++ src/babashka/main.clj | 3 +++ test/babashka/main_test.clj | 6 ++++++ 7 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/babashka/impl/yaml.clj diff --git a/README.md b/README.md index 03c8065e..aa26ca3d 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,8 @@ enumerated explicitly. - [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv` - [`cheshire.core`](https://github.com/dakrone/cheshire) aliased as `json` - [`cognitect.transit`](https://github.com/cognitect/transit-clj) aliased as `transit` -- [`bencode.core`](https://github.com/nrepl/bencode) aliased as `bencode`: `read-bencode`, `write-bencode`. +- [`clj-yaml.core`](https://github.com/clj-commons/clj-yaml) alias as `yaml` +- [`bencode.core`](https://github.com/nrepl/bencode) aliased as `bencode`: `read-bencode`, `write-bencode` A selection of java classes are available, see `babashka/impl/classes.clj`. diff --git a/deps.edn b/deps.edn index 15f1651e..0bb856ed 100644 --- a/deps.edn +++ b/deps.edn @@ -9,9 +9,8 @@ org.clojure/data.csv {:mvn/version "1.0.0"}, cheshire {:mvn/version "5.10.0"} fipp {:mvn/version "0.6.22"} - com.cognitect/transit-clj {:mvn/version "1.0.324"} - ;; nrepl/bencode {:mvn/version "1.0.0"} - } + clj-commons/clj-yaml {:mvn/version "0.7.1"} + com.cognitect/transit-clj {:mvn/version "1.0.324"}} :aliases {:main {:main-opts ["-m" "babashka.main"]} :profile diff --git a/doc/dev.md b/doc/dev.md index 5bc22ec9..b1eededf 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -61,6 +61,9 @@ $ BABASHKA_XMX="-J-Xmx4g" script/compile Keep notes here about how adding libraries and classes to Babashka affects the binary size. +2020/03/29 Added clj-yaml for parsing and generating yaml. +45196996 - 42626884 = 2570kb added. + 2020/03/28 Added java.nio.file.FileSystem(s) to support extracting zip files 42562284 - 42021244 = 541kb added. diff --git a/project.clj b/project.clj index 43676d95..f6ea4fc8 100644 --- a/project.clj +++ b/project.clj @@ -21,8 +21,8 @@ [org.clojure/data.csv "1.0.0"] [cheshire "5.10.0"] [fipp "0.6.22"] - [com.cognitect/transit-clj "1.0.324"] - #_[nrepl/bencode "1.0.0"]] + [clj-commons/clj-yaml "0.7.1"] + [com.cognitect/transit-clj "1.0.324"]] :profiles {:test {:dependencies [[clj-commons/conch "0.9.2"] [com.clojure-goes-fast/clj-async-profiler "0.4.0"]]} :uberjar {:global-vars {*assert* false} diff --git a/src/babashka/impl/yaml.clj b/src/babashka/impl/yaml.clj new file mode 100644 index 00000000..1c1206c0 --- /dev/null +++ b/src/babashka/impl/yaml.clj @@ -0,0 +1,11 @@ +(ns babashka.impl.yaml + {:no-doc true} + (:require [clj-yaml.core :as yaml] + [sci.impl.namespaces :refer [copy-var]] + [sci.impl.vars :as vars])) + +(def yns (vars/->SciNamespace 'clj-yaml.core nil)) + +(def yaml-namespace + {'generate-string (copy-var yaml/generate-string yns) + 'parse-string (copy-var yaml/parse-string yns)}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index d183a1bb..d4051a25 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -28,6 +28,7 @@ [clojure.java.io :as io] [clojure.stacktrace :refer [print-stack-trace]] [clojure.string :as str] + [babashka.impl.yaml :refer [yaml-namespace]] [sci.addons :as addons] [sci.core :as sci] [sci.impl.interpreter :refer [eval-string*]] @@ -246,6 +247,7 @@ Everything after that is bound to *command-line-args*.")) async clojure.core.async csv clojure.data.csv json cheshire.core + yaml clj-yaml.core curl babashka.curl transit cognitect.transit bencode bencode.core}) @@ -279,6 +281,7 @@ Everything after that is bound to *command-line-args*.")) 'clojure.repl {'demunge demunge} 'clojure.test t/clojure-test-namespace 'babashka.classpath {'add-classpath add-classpath*} + 'clj-yaml.core yaml-namespace 'clojure.pprint pprint-namespace 'babashka.curl curl-namespace 'cognitect.transit transit-namespace diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 057f8b81..2502cb39 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -402,6 +402,12 @@ (bb nil (format "(.deleteOnExit (io/file \"%s\"))" p)) (is (false? (.exists f)))))) + +(deftest yaml-test + (is (str/starts-with? + (bb nil "(yaml/generate-string [{:name \"John Smith\", :age 33} {:name \"Mary Smith\", :age 27}])") + "-"))) + (deftest statsd-client-test (is (= :success (bb nil " (load-file (io/file \"test-resources\" \"babashka\" \"statsd.clj\")) From 66ba9007acab6112992e53afd7d0c24314716d8e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 12:52:01 +0200 Subject: [PATCH 239/264] v0.0.85 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 1cb12897..691cb279 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.85-SNAPSHOT \ No newline at end of file +0.0.85 \ No newline at end of file From 84cd8c7e9dfeddfd1a1c4566ac47a29c35b0366a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 13:02:55 +0200 Subject: [PATCH 240/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 50a03442..691cb279 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.84 \ No newline at end of file +0.0.85 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 691cb279..feb0961d 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.85 \ No newline at end of file +0.0.86-SNAPSHOT \ No newline at end of file From 2241ce67ddf37469c5248c00091956eca450ad22 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 21:09:20 +0200 Subject: [PATCH 241/264] babashka.curl: add streaming test --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index b6ad0648..13bdaf39 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit b6ad0648d8e59220924ea196e1ebac50cf6af503 +Subproject commit 13bdaf39b44e9e828bafab4f60fc497a2e9685fd From 9be4c7e9a982a70540feb81b41e642a672a0f8dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 15 Apr 2020 23:08:30 +0200 Subject: [PATCH 242/264] Improve statsd test --- test/babashka/main_test.clj | 8 -------- test/babashka/udp_test.clj | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 test/babashka/udp_test.clj diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 2502cb39..bbe33abb 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -402,19 +402,11 @@ (bb nil (format "(.deleteOnExit (io/file \"%s\"))" p)) (is (false? (.exists f)))))) - (deftest yaml-test (is (str/starts-with? (bb nil "(yaml/generate-string [{:name \"John Smith\", :age 33} {:name \"Mary Smith\", :age 27}])") "-"))) -(deftest statsd-client-test - (is (= :success (bb nil " -(load-file (io/file \"test-resources\" \"babashka\" \"statsd.clj\")) -(require '[statsd-client :as c]) -(c/increment :foo) -:success")))) - ;;;; Scratch (comment diff --git a/test/babashka/udp_test.clj b/test/babashka/udp_test.clj new file mode 100644 index 00000000..5c0f3730 --- /dev/null +++ b/test/babashka/udp_test.clj @@ -0,0 +1,25 @@ +(ns babashka.udp-test + (:require [babashka.test-utils :as tu] + [clojure.test :refer [deftest is]]) + (:import [java.io StringWriter] + [java.net DatagramPacket DatagramSocket])) + +(set! *warn-on-reflection* true) + +(deftest udp-test + (let [server (DatagramSocket. 8125) + sw (StringWriter.) + fut (future + (let [buf (byte-array 1024) + packet (DatagramPacket. buf 1024) + _ (.receive server packet) + non-zero-bytes (filter #(not (zero? %)) (.getData packet)) + non-zero-bytes (byte-array non-zero-bytes)] + (binding [*out* sw] + (println (String. non-zero-bytes "UTF-8")))))] + (while (not (realized? fut)) + (tu/bb nil + "-e" "(load-file (io/file \"test-resources\" \"babashka\" \"statsd.clj\"))" + "-e" "(require '[statsd-client :as c])" + "-e" "(c/increment :foo)")) + (is (= ":foo:1|c\n" (str sw))))) From 88d2ca0b3970e4902456af78c7860ee0ce582692 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 09:24:24 +0200 Subject: [PATCH 243/264] borkdude/babashka#317: add apropos --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 22bd9221..668ebb4f 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 22bd92211c82b885b079b94d175eb821edb2e9b4 +Subproject commit 668ebb4f674e0d60f571b1352f712de38ef32182 From 1dd387323c1ecf53684b1881b3e243ab1dece650 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 09:44:57 +0200 Subject: [PATCH 244/264] borkdude/sci#306 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 668ebb4f..f7973dc4 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 668ebb4f674e0d60f571b1352f712de38ef32182 +Subproject commit f7973dc4ce904b34bd2a007bdceb141cbcaa41d2 From da0f4a6fe3d667a12a93b8a1451fbd8ac806f267 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 11:22:47 +0200 Subject: [PATCH 245/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index f7973dc4..73712503 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit f7973dc4ce904b34bd2a007bdceb141cbcaa41d2 +Subproject commit 737125035bc26254689e256e7164ddc7be80f9de From bc4fab37cd79d7fdc6b617255aea827f0bfbdf62 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 15:33:25 +0200 Subject: [PATCH 246/264] Enable jar protocol --- script/compile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/compile b/script/compile index 3d1562a4..c1515cbc 100755 --- a/script/compile +++ b/script/compile @@ -38,7 +38,7 @@ args=( -jar $BABASHKA_JAR \ --initialize-at-run-time=java.lang.Math\$RandomNumberGeneratorHolder \ --initialize-at-build-time \ -H:Log=registerResource: \ - -H:EnableURLProtocols=http,https \ + -H:EnableURLProtocols=jar,http,https \ --enable-all-security-services \ -H:+JNI \ --verbose \ From 228020f2e81067d1fcd23f6ae5bc93d0c936efcc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 16:43:06 +0200 Subject: [PATCH 247/264] minor --- src/babashka/main.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index d4051a25..0c2026b3 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -23,12 +23,12 @@ [babashka.impl.test :as t] [babashka.impl.tools.cli :refer [tools-cli-namespace]] [babashka.impl.transit :refer [transit-namespace]] + [babashka.impl.yaml :refer [yaml-namespace]] [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] [clojure.stacktrace :refer [print-stack-trace]] [clojure.string :as str] - [babashka.impl.yaml :refer [yaml-namespace]] [sci.addons :as addons] [sci.core :as sci] [sci.impl.interpreter :refer [eval-string*]] From 1c4014f7f92d83ff7546ab4a7e813fd48ed00cab Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 20:39:42 +0200 Subject: [PATCH 248/264] sci: resolve as fn, clojure.repl/source --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 73712503..2580c579 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 737125035bc26254689e256e7164ddc7be80f9de +Subproject commit 2580c5793e8c97b627a938afc3026ac0f8c38973 From 26473b8a4230054af51adae8cb03ef162b3af140 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 20:57:59 +0200 Subject: [PATCH 249/264] [#317] add clojure.repl/source --- script/compile | 2 +- test/babashka/main_test.clj | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/script/compile b/script/compile index c1515cbc..3d1562a4 100755 --- a/script/compile +++ b/script/compile @@ -38,7 +38,7 @@ args=( -jar $BABASHKA_JAR \ --initialize-at-run-time=java.lang.Math\$RandomNumberGeneratorHolder \ --initialize-at-build-time \ -H:Log=registerResource: \ - -H:EnableURLProtocols=jar,http,https \ + -H:EnableURLProtocols=http,https \ --enable-all-security-services \ -H:+JNI \ --verbose \ diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index bbe33abb..956e1b08 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -122,6 +122,7 @@ (deftest load-file-test (let [tmp (java.io.File/createTempFile "script" ".clj")] + (.deleteOnExit tmp) (spit tmp "(ns foo) (defn foo [x y] (+ x y)) (defn bar [x y] (* x y))") (is (= "120\n" (test-utils/bb nil (format "(load-file \"%s\") (foo/bar (foo/foo 10 30) 3)" (.getPath tmp))))) @@ -130,6 +131,31 @@ (bb nil (format "(ns start-ns) (load-file \"%s\") (ns-name *ns*)" (.getPath tmp)))))))) +(deftest repl-source-test + (let [tmp (java.io.File/createTempFile "lib" ".clj") + name (str/replace (.getName tmp) ".clj" "") + dir (.getParent tmp)] + (.deleteOnExit tmp) + (testing "print source from loaded file" + (spit tmp (format " +(ns %s) + +(defn foo [x y] + (+ x y))" name)) + (is (= "(defn foo [x y]\n (+ x y))\n" + (bb nil (format " +(load-file \"%s\") +(require '[clojure.repl :refer [source]]) +(with-out-str (source %s/foo))" + (.getPath tmp) + 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))))))) + (deftest eval-test (is (= "120\n" (test-utils/bb nil "(eval '(do (defn foo [x y] (+ x y)) (defn bar [x y] (* x y)) From 7fa410b404a8b65e3d8c7f2af1e0b2ada142ca63 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 22:43:37 +0200 Subject: [PATCH 250/264] [#263] add more clj-yaml functions, run tests from source --- script/lib_tests/clj_yaml_tests | 23 +++++++++++++++++++++++ script/run_lib_tests | 1 + src/babashka/impl/classes.clj | 4 +++- src/babashka/impl/yaml.clj | 4 +++- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100755 script/lib_tests/clj_yaml_tests diff --git a/script/lib_tests/clj_yaml_tests b/script/lib_tests/clj_yaml_tests new file mode 100755 index 00000000..0a2ae371 --- /dev/null +++ b/script/lib_tests/clj_yaml_tests @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -eo pipefail + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + +$BB_CMD -e " +(require '[clojure.java.io :as io]) +(def test-file (io/file (System/getProperty \"java.io.tmpdir\") \"core_test.clj\")) +(io/copy + (io/input-stream \"https://raw.githubusercontent.com/clj-commons/clj-yaml/master/test/clj_yaml/core_test.clj\") + test-file) +(load-file test-file) +(require '[clojure.test :as t]) +(let [{:keys [:test :pass :fail :error]} (t/run-tests 'clj-yaml.core-test)] + (when-not (pos? test) + (System/exit 1)) + (System/exit (+ fail error))) +" diff --git a/script/run_lib_tests b/script/run_lib_tests index 3130036b..49ac84db 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -12,3 +12,4 @@ script/lib_tests/babashka_curl_test script/lib_tests/cprop_test script/lib_tests/comb_test script/lib_tests/arrangement_test +script/lib_tests/clj_yaml_test diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 21a74071..57707e8a 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -112,7 +112,9 @@ java.util.zip.InflaterInputStream java.util.zip.DeflaterInputStream java.util.zip.GZIPInputStream - java.util.zip.GZIPOutputStream] + java.util.zip.GZIPOutputStream + org.yaml.snakeyaml.error.YAMLException + ] :constructors [clojure.lang.Delay clojure.lang.MapEntry clojure.lang.LineNumberingPushbackReader diff --git a/src/babashka/impl/yaml.clj b/src/babashka/impl/yaml.clj index 1c1206c0..33ad7a4f 100644 --- a/src/babashka/impl/yaml.clj +++ b/src/babashka/impl/yaml.clj @@ -7,5 +7,7 @@ (def yns (vars/->SciNamespace 'clj-yaml.core nil)) (def yaml-namespace - {'generate-string (copy-var yaml/generate-string yns) + {'mark (copy-var yaml/mark yns) + 'unmark (copy-var yaml/unmark yns) + 'generate-string (copy-var yaml/generate-string yns) 'parse-string (copy-var yaml/parse-string yns)}) From b9b8db45026dd97fe39a41db297056ade4376c4f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 16 Apr 2020 23:24:20 +0200 Subject: [PATCH 251/264] Fix tests --- .../{clj_yaml_tests => clj_yaml_test} | 8 +- script/lib_tests/clojure_data_csv_test | 19 ++ script/run_lib_tests | 1 + src/babashka/impl/classes.clj | 14 +- .../lib_tests/clj_yaml/core_test.clj | 202 ++++++++++++++++++ .../lib_tests/clojure/data/csv_test.clj | 79 +++++++ 6 files changed, 306 insertions(+), 17 deletions(-) rename script/lib_tests/{clj_yaml_tests => clj_yaml_test} (58%) create mode 100755 script/lib_tests/clojure_data_csv_test create mode 100644 test-resources/lib_tests/clj_yaml/core_test.clj create mode 100644 test-resources/lib_tests/clojure/data/csv_test.clj diff --git a/script/lib_tests/clj_yaml_tests b/script/lib_tests/clj_yaml_test similarity index 58% rename from script/lib_tests/clj_yaml_tests rename to script/lib_tests/clj_yaml_test index 0a2ae371..a20a5279 100755 --- a/script/lib_tests/clj_yaml_tests +++ b/script/lib_tests/clj_yaml_test @@ -8,13 +8,9 @@ else BB_CMD="lein bb" fi -$BB_CMD -e " +$BB_CMD -cp test-resources/lib_tests -e " (require '[clojure.java.io :as io]) -(def test-file (io/file (System/getProperty \"java.io.tmpdir\") \"core_test.clj\")) -(io/copy - (io/input-stream \"https://raw.githubusercontent.com/clj-commons/clj-yaml/master/test/clj_yaml/core_test.clj\") - test-file) -(load-file test-file) +(require '[clj-yaml.core-test]) (require '[clojure.test :as t]) (let [{:keys [:test :pass :fail :error]} (t/run-tests 'clj-yaml.core-test)] (when-not (pos? test) diff --git a/script/lib_tests/clojure_data_csv_test b/script/lib_tests/clojure_data_csv_test new file mode 100755 index 00000000..c229ab92 --- /dev/null +++ b/script/lib_tests/clojure_data_csv_test @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -eo pipefail + +if [ "$BABASHKA_TEST_ENV" = "native" ]; then + BB_CMD="./bb" +else + BB_CMD="lein bb" +fi + +$BB_CMD -cp test-resources/lib_tests -e " +(require '[clojure.java.io :as io]) +(require '[clojure.data.csv-test]) +(require '[clojure.test :as t]) +(let [{:keys [:test :pass :fail :error]} (t/run-tests 'clojure.data.csv-test)] + (when-not (pos? test) + (System/exit 1)) + (System/exit (+ fail error))) +" diff --git a/script/run_lib_tests b/script/run_lib_tests index 49ac84db..b50b845d 100755 --- a/script/run_lib_tests +++ b/script/run_lib_tests @@ -13,3 +13,4 @@ script/lib_tests/cprop_test script/lib_tests/comb_test script/lib_tests/arrangement_test script/lib_tests/clj_yaml_test +script/lib_tests/clojure_data_csv_test diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 57707e8a..42662e87 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -1,19 +1,10 @@ (ns babashka.impl.classes {:no-doc true} (:require - [cheshire.core :as json] - #_[clojure.string :as str])) - -;; (def os-name (str/lower-case (System/getProperty "os.name"))) -;; (def os (cond (str/includes? os-name "mac") :mac -;; (or (str/includes? os-name "nix") -;; (str/includes? os-name "nux")) :linux -;; (str/includes? os-name "win") :windows)) -;; (def unix-like? (or (identical? os :linux) -;; (identical? os :mac))) + [cheshire.core :as json])) (def classes - '{:all [clojure.lang.ExceptionInfo + `{:all [clojure.lang.ExceptionInfo java.io.BufferedReader java.io.BufferedWriter java.io.ByteArrayInputStream @@ -114,6 +105,7 @@ java.util.zip.GZIPInputStream java.util.zip.GZIPOutputStream org.yaml.snakeyaml.error.YAMLException + ~(symbol "[B") ] :constructors [clojure.lang.Delay clojure.lang.MapEntry diff --git a/test-resources/lib_tests/clj_yaml/core_test.clj b/test-resources/lib_tests/clj_yaml/core_test.clj new file mode 100644 index 00000000..5d475f32 --- /dev/null +++ b/test-resources/lib_tests/clj_yaml/core_test.clj @@ -0,0 +1,202 @@ +(ns clj-yaml.core-test + (:require [clojure.test :refer (deftest testing is)] + [clojure.string :as string] + [clj-yaml.core :refer [parse-string unmark generate-string]]) + (:import [java.util Date])) + +(def nested-hash-yaml + "root:\n childa: a\n childb: \n grandchild: \n greatgrandchild: bar\n") + +(def list-yaml + "--- # Favorite Movies\n- Casablanca\n- North by Northwest\n- The Man Who Wasn't There") + +(def hashes-lists-yaml " +items: + - part_no: A4786 + descrip: Water Bucket (Filled) + price: 1.47 + quantity: 4 + + - part_no: E1628 + descrip: High Heeled \"Ruby\" Slippers + price: 100.27 + quantity: 1 + owners: + - Dorthy + - Wicked Witch of the East +") + +(def inline-list-yaml +"--- # Shopping list +[milk, pumpkin pie, eggs, juice] +") + +(def inline-hash-yaml + "{name: John Smith, age: 33}") + +(def list-of-hashes-yaml " +- {name: John Smith, age: 33} +- name: Mary Smith + age: 27 +") + +(def hashes-of-lists-yaml " +men: [John Smith, Bill Jones] +women: + - Mary Smith + - Susan Williams +") + +(def typed-data-yaml " +the-bin: !!binary 0101") + +(def io-file-typed-data-yaml " +!!java.io.File") + +(def set-yaml " +--- !!set +? Mark McGwire +? Sammy Sosa +? Ken Griff") + +(deftest parse-hash + (let [parsed (parse-string "foo: bar")] + (is (= "bar" (parsed :foo))))) + +(deftest parse-hash-with-numeric-key + (let [parsed (parse-string "123: 456")] + (is (= 456 (parsed 123))))) + +(deftest parse-hash-with-complex-key + (let [parsed (parse-string "[1, 2]: 3")] + (is (= 3 (parsed [1, 2]))))) + +(deftest parse-nested-hash + (let [parsed (parse-string nested-hash-yaml)] + (is (= "a" ((parsed :root) :childa))) + (is (= "bar" ((((parsed :root) :childb) :grandchild) :greatgrandchild))))) + +(deftest parse-list + (let [parsed (parse-string list-yaml)] + (is (= "Casablanca" (first parsed))) + (is (= "North by Northwest" (nth parsed 1))) + (is (= "The Man Who Wasn't There" (nth parsed 2))))) + +(deftest parse-nested-hash-and-list + (let [parsed (parse-string hashes-lists-yaml)] + (is (= "A4786" ((first (parsed :items)) :part_no))) + (is (= "Dorthy" (first ((nth (parsed :items) 1) :owners)))))) + +(deftest parse-inline-list + (let [parsed (parse-string inline-list-yaml)] + (is (= "milk" (first parsed))) + (is (= "pumpkin pie" (nth parsed 1))) + (is (= "eggs" (nth parsed 2))) + (is (= "juice" (last parsed))))) + +(deftest parse-inline-hash + (let [parsed (parse-string inline-hash-yaml)] + (is (= "John Smith" (parsed :name))) + (is (= 33 (parsed :age))))) + +(deftest parse-list-of-hashes + (let [parsed (parse-string list-of-hashes-yaml)] + (is (= "John Smith" ((first parsed) :name))) + (is (= 33 ((first parsed) :age))) + (is (= "Mary Smith" ((nth parsed 1) :name))) + (is (= 27 ((nth parsed 1) :age))))) + +(deftest hashes-of-lists + (let [parsed (parse-string hashes-of-lists-yaml)] + (is (= "John Smith" (first (parsed :men)))) + (is (= "Bill Jones" (last (parsed :men)))) + (is (= "Mary Smith" (first (parsed :women)))) + (is (= "Susan Williams" (last (parsed :women)))))) + +(deftest h-set + (is (= #{"Mark McGwire" "Ken Griff" "Sammy Sosa"} + (parse-string set-yaml)))) + +(deftest typed-data + (let [parsed (parse-string typed-data-yaml)] + (is (= (Class/forName "[B") (type (:the-bin parsed)))))) + +(deftest disallow-arbitrary-typed-data + (is (thrown? org.yaml.snakeyaml.error.YAMLException + (parse-string io-file-typed-data-yaml)))) + +(deftest keywordized + (is (= "items" + (-> hashes-lists-yaml + (parse-string :keywords false) + ffirst)))) + +(deftest not-keywordized-in-lists + (is (every? string? + (-> "[{b: c, c: d}]" + (parse-string :keywords false) + first + keys)))) + +(deftest marking-source-position-works + (let [parsed (parse-string inline-list-yaml :mark true)] + ;; The list starts at the beginning of line 1. + (is (= 1 (-> parsed :start :line))) + (is (= 0 (-> parsed :start :column))) + ;; The first item starts at the second character of line 1. + (is (= 1 (-> parsed unmark first :start :line))) + (is (= 1 (-> parsed unmark first :start :column))) + ;; The first item ends at the fifth character of line 1. + (is (= 1 (-> parsed unmark first :end :line))) + (is (= 5 (-> parsed unmark first :end :column))))) + +(deftest text-wrapping + (let [data + {:description + "Big-picture diagram showing how our top-level systems and stakeholders interact"}] + (testing "long lines of text should not be wrapped" + ;; clj-yaml 0.5.6 used SnakeYAML 1.13 which by default did *not* split long lines. + ;; clj-yaml 0.6.0 upgraded to SnakeYAML 1.23 which by default *did* split long lines. + ;; This test ensures that generate-string uses the older behavior by default, for the sake + ;; of stability, i.e. backwards compatibility. + (is + (= "{description: Big-picture diagram showing how our top-level systems and stakeholders interact}\n" + (generate-string data)))))) + +(deftest dump-opts + (let [data [{:age 33 :name "jon"} {:age 44 :name "boo"}]] + (is (= "- age: 33\n name: jon\n- age: 44\n name: boo\n" + (generate-string data :dumper-options {:flow-style :block}))) + (is (= "[{age: 33, name: jon}, {age: 44, name: boo}]\n" + (generate-string data :dumper-options {:flow-style :flow}))))) + +;; TODO: this test is failing in GraalVM +#_(deftest parse-time + (testing "clj-time parses timestamps with more than millisecond precision correctly." + (let [timestamp "2001-11-23 15:02:31.123456 -04:00" + expected 1006542151123] + (is (= (.getTime ^Date (parse-string timestamp)) expected))))) + +(deftest maps-are-ordered + (let [parsed (parse-string hashes-lists-yaml) + [first second] (:items parsed)] + (is (= (keys first) '(:part_no :descrip :price :quantity))) + (is (= (keys second)'(:part_no :descrip :price :quantity :owners))))) + + +(deftest nulls-are-fine + (testing "nil does not blow up" + (let [res (parse-string "- f:")] + (is (= [{:f nil}] res)) + (is (str res))))) + +(deftest emoji-can-be-parsed + (let [yaml "{emoji: 💣}"] + (is (= yaml (-> yaml + (generate-string) + (parse-string) + (string/trim))))) + + (testing "emoji in comments are OK too" + (let [yaml "# 💣 emoji in a comment\n42"] + (is (= 42 (parse-string yaml)))))) diff --git a/test-resources/lib_tests/clojure/data/csv_test.clj b/test-resources/lib_tests/clojure/data/csv_test.clj new file mode 100644 index 00000000..8dfa7dfb --- /dev/null +++ b/test-resources/lib_tests/clojure/data/csv_test.clj @@ -0,0 +1,79 @@ +(ns clojure.data.csv-test + (:use + [clojure.test :only (deftest is)] + [clojure.data.csv :only (read-csv write-csv)]) + (:import + [java.io Reader StringReader StringWriter EOFException])) + +(def ^{:private true} simple + "Year,Make,Model +1997,Ford,E350 +2000,Mercury,Cougar +") + +(def ^{:private true} simple-alt-sep + "Year;Make;Model +1997;Ford;E350 +2000;Mercury;Cougar +") + +(def ^{:private true} complicated + "1997,Ford,E350,\"ac, abs, moon\",3000.00 +1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00 +1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",\"\",5000.00 +1996,Jeep,Grand Cherokee,\"MUST SELL! +air, moon roof, loaded\",4799.00") + +(deftest reading + (let [csv (read-csv simple)] + (is (= (count csv) 3)) + (is (= (count (first csv)) 3)) + (is (= (first csv) ["Year" "Make" "Model"])) + (is (= (last csv) ["2000" "Mercury" "Cougar"]))) + (let [csv (read-csv simple-alt-sep :separator \;)] + (is (= (count csv) 3)) + (is (= (count (first csv)) 3)) + (is (= (first csv) ["Year" "Make" "Model"])) + (is (= (last csv) ["2000" "Mercury" "Cougar"]))) + (let [csv (read-csv complicated)] + (is (= (count csv) 4)) + (is (= (count (first csv)) 5)) + (is (= (first csv) + ["1997" "Ford" "E350" "ac, abs, moon" "3000.00"])) + (is (= (last csv) + ["1996" "Jeep" "Grand Cherokee", "MUST SELL!\nair, moon roof, loaded" "4799.00"])))) + + +(deftest reading-and-writing + (let [string-writer (StringWriter.)] + (->> simple read-csv (write-csv string-writer)) + (is (= simple + (str string-writer))))) + +(deftest throw-if-quoted-on-eof + (let [s "ab,\"de,gh\nij,kl,mn"] + (try + (doall (read-csv s)) + (is false "No exception thrown") + (catch Exception e + (is (or (instance? java.io.EOFException e) + (and (instance? RuntimeException e) + (instance? java.io.EOFException (.getCause e))))))))) + +(deftest parse-line-endings + (let [csv (read-csv "Year,Make,Model\n1997,Ford,E350")] + (is (= 2 (count csv))) + (is (= ["Year" "Make" "Model"] (first csv))) + (is (= ["1997" "Ford" "E350"] (second csv)))) + (let [csv (read-csv "Year,Make,Model\r\n1997,Ford,E350")] + (is (= 2 (count csv))) + (is (= ["Year" "Make" "Model"] (first csv))) + (is (= ["1997" "Ford" "E350"] (second csv)))) + (let [csv (read-csv "Year,Make,Model\r1997,Ford,E350")] + (is (= 2 (count csv))) + (is (= ["Year" "Make" "Model"] (first csv))) + (is (= ["1997" "Ford" "E350"] (second csv)))) + (let [csv (read-csv "Year,Make,\"Model\"\r1997,Ford,E350")] + (is (= 2 (count csv))) + (is (= ["Year" "Make" "Model"] (first csv))) + (is (= ["1997" "Ford" "E350"] (second csv))))) From 023a02777274ac2f027d2914373ddc846aa1127e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 17 Apr 2020 11:19:32 +0200 Subject: [PATCH 252/264] Add note --- test-resources/lib_tests/clj_yaml/core_test.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/test-resources/lib_tests/clj_yaml/core_test.clj b/test-resources/lib_tests/clj_yaml/core_test.clj index 5d475f32..0e75a4d6 100644 --- a/test-resources/lib_tests/clj_yaml/core_test.clj +++ b/test-resources/lib_tests/clj_yaml/core_test.clj @@ -171,6 +171,7 @@ the-bin: !!binary 0101") (generate-string data :dumper-options {:flow-style :flow}))))) ;; TODO: this test is failing in GraalVM +;; Could be related to https://github.com/oracle/graal/issues/2234 #_(deftest parse-time (testing "clj-time parses timestamps with more than millisecond precision correctly." (let [timestamp "2001-11-23 15:02:31.123456 -04:00" From 789f321e049922150ac787f71b37126fabcba9e8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 17 Apr 2020 20:10:12 +0200 Subject: [PATCH 253/264] borkdude/babashka.curl#17 --- babashka.curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babashka.curl b/babashka.curl index 13bdaf39..a9e9fe83 160000 --- a/babashka.curl +++ b/babashka.curl @@ -1 +1 @@ -Subproject commit 13bdaf39b44e9e828bafab4f60fc497a2e9685fd +Subproject commit a9e9fe83d56b020071c1a3bbeb4656e53c8a988d From d5dda0d26ee8efe8f33bd2a170cc215280a9e02f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 17 Apr 2020 20:10:46 +0200 Subject: [PATCH 254/264] v0.0.86 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index feb0961d..4c4317b7 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.86-SNAPSHOT \ No newline at end of file +0.0.86 \ No newline at end of file From 4021f1bf917f7e0194322d1a5e6b7b2de4dd11e1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 17 Apr 2020 20:20:50 +0200 Subject: [PATCH 255/264] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 691cb279..4c4317b7 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.85 \ No newline at end of file +0.0.86 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 4c4317b7..baa5f3ce 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.86 \ No newline at end of file +0.0.87-SNAPSHOT \ No newline at end of file From 99c152c8f5e8207d532c5e4cd6e9c5314750fc4d Mon Sep 17 00:00:00 2001 From: jess Date: Fri, 17 Apr 2020 12:16:45 -0700 Subject: [PATCH 256/264] Added financial contributors to the README (#360) --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa26ca3d..902fc241 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) -[![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) +[![Financial Contributors on Open Collective](https://opencollective.com/babashka/all/badge.svg?label=financial+contributors)](https://opencollective.com/babashka) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) [![project chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://app.slack.com/client/T03RZGPFR/CLX41ASCS) @@ -1254,6 +1254,36 @@ $ examples/which.clj rg - [contributors](https://github.com/borkdude/babashka/graphs/contributors) and other users posting issues with bug reports and ideas +## Contributors + +### Code Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + + +### Financial Contributors + +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 Copyright © 2019-2020 Michiel Borkent From b8d916c5e725f7eac69044f9e6ab94c345f4c538 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 17 Apr 2020 22:05:22 +0200 Subject: [PATCH 257/264] docs --- CONTRIBUTING.md | 1 + README.md | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0a177eb9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +See [doc/dev.md](doc/dev.md). diff --git a/README.md b/README.md index 902fc241..7a4c603d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) -[![Financial Contributors on Open Collective](https://opencollective.com/babashka/all/badge.svg?label=financial+contributors)](https://opencollective.com/babashka) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) [![project chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://app.slack.com/client/T03RZGPFR/CLX41ASCS) - - +[![Financial Contributors on Open Collective](https://opencollective.com/babashka/all/badge.svg?label=financial+contributors)](https://opencollective.com/babashka) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash. @@ -1258,7 +1256,7 @@ $ examples/which.clj rg ### Code Contributors -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. +This project exists thanks to all the people who contribute. [[Contribute](doc/dev.md)]. ### Financial Contributors From 255c400e0acf57599d6154193df88b445b0cc390 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 00:09:22 +0200 Subject: [PATCH 258/264] [#362] bump edamame: preserve location metadata in fn literal --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index 0bb856ed..485ae6a4 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {:paths ["src" "sci/src" "babashka.curl/src" "resources" "sci/resources"], :deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}, org.clojure/tools.reader {:mvn/version "1.3.2"}, - borkdude/edamame {:mvn/version "0.0.11-alpha.8"}, + borkdude/edamame {:mvn/version "0.0.11-alpha.9"}, borkdude/graal.locking {:mvn/version "0.0.2"}, borkdude/sci.impl.reflector {:mvn/version "0.0.1"} org.clojure/core.async {:mvn/version "1.0.567"}, diff --git a/project.clj b/project.clj index f6ea4fc8..11dc5018 100644 --- a/project.clj +++ b/project.clj @@ -13,7 +13,7 @@ :resource-paths ["resources" "sci/resources"] :dependencies [[org.clojure/clojure "1.10.2-alpha1"] [org.clojure/tools.reader "1.3.2"] - [borkdude/edamame "0.0.11-alpha.8"] + [borkdude/edamame "0.0.11-alpha.9"] [borkdude/graal.locking "0.0.2"] [borkdude/sci.impl.reflector "0.0.1"] [org.clojure/core.async "1.0.567"] diff --git a/sci b/sci index 2580c579..e438f66b 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 2580c5793e8c97b627a938afc3026ac0f8c38973 +Subproject commit e438f66bd3ae3bf3e2c66ea2faf4f64bb1730008 From eac3cea725845088adf1971a977d941174551912 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 09:23:04 +0200 Subject: [PATCH 259/264] doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a4c603d..595e83c9 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,8 @@ $ cat script.clj ## [Running a REPL](doc/repl.md) Babashka offers a REPL, a socket REPL and an nREPL server. Look -[here](doc/repl.md) for more information. +[here](doc/repl.md) for more information on how to use and integrate them with +your editor. ## Preloads From d4eac5f725f045639366a159195ca137f0a24e96 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 10:05:24 +0200 Subject: [PATCH 260/264] Add clojure.core/memoize --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index e438f66b..513f9346 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit e438f66bd3ae3bf3e2c66ea2faf4f64bb1730008 +Subproject commit 513f93460476085b645b6c93d4422b437247f4f8 From 94ae3ba0ca11e4b7c972eee6bdeaf86d1c206675 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 10:28:01 +0200 Subject: [PATCH 261/264] [#364] better error for invalid interop --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 513f9346..68a36b59 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 513f93460476085b645b6c93d4422b437247f4f8 +Subproject commit 68a36b59f3bd2c7fa4bf7bfd57545a743a8e2ac0 From 7270970a0dbe2ac4f56ab23400cc171af1acf61e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 10:33:19 +0200 Subject: [PATCH 262/264] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 68a36b59..ec25c8b2 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 68a36b59f3bd2c7fa4bf7bfd57545a743a8e2ac0 +Subproject commit ec25c8b2b8d1aef109c6480e8633d23c2e929a8d From 14dca029d32caf0cf68565d2fd5cf8d5f4458dc3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 12:06:07 +0200 Subject: [PATCH 263/264] sci: add clojure.core/load-string --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index ec25c8b2..ead5dd7c 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit ec25c8b2b8d1aef109c6480e8633d23c2e929a8d +Subproject commit ead5dd7c25e0e38cb6244077ec9e57e00665cde9 From 8072df2b97207c46340c64912597e05eed726077 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 18 Apr 2020 18:10:32 +0200 Subject: [PATCH 264/264] Dynamically find svm.jar --- script/compile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script/compile b/script/compile index 3d1562a4..69ed5424 100755 --- a/script/compile +++ b/script/compile @@ -17,7 +17,8 @@ BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION) export JAVA_HOME=$GRAALVM_HOME -$GRAALVM_HOME/bin/javac -cp $GRAALVM_HOME/jre/lib/svm/builder/svm.jar resources/CutOffCoreServicesDependencies.java +SVM_JAR=$(find "$GRAALVM_HOME" | grep svm.jar) +$GRAALVM_HOME/bin/javac -cp "$SVM_JAR" resources/CutOffCoreServicesDependencies.java if [ -z "$BABASHKA_JAR" ]; then lein with-profiles +reflection do run