Merge branch 'master' into feature-malli

This commit is contained in:
Michiel Borkent 2021-04-01 21:57:11 +02:00
commit 151583e0b5
54 changed files with 1608 additions and 507 deletions

View file

@ -225,6 +225,95 @@ jobs:
name: Publish artifact link to Slack name: Publish artifact link to Slack
command: | command: |
./bb .circleci/script/publish_artifact.clj || true ./bb .circleci/script/publish_artifact.clj || true
linux-aarch64:
machine:
enabled: true
image: ubuntu-2004:202101-01
resource_class: arm.large
working_directory: ~/repo
environment:
LEIN_ROOT: "true"
GRAALVM_HOME: /home/circleci/graalvm-ce-java11-21.0.0
BABASHKA_PLATFORM: linux # used in release script
BABASHKA_ARCH: aarch64
BABASHKA_TEST_ENV: native
BABASHKA_XMX: "-J-Xmx6500m"
steps:
- checkout
- run:
name: "Pull Submodules"
command: |
git submodule init
git submodule update
- run:
name: "Short circuit on SNAPSHOT"
command: |
VERSION=$(cat resources/BABASHKA_VERSION)
if [[ "$VERSION" == *-SNAPSHOT ]]
then
circleci task halt
fi
- restore_cache:
keys:
- linux-aarch64-{{ checksum "project.clj" }}-{{ checksum ".circleci/config.yml" }}
- run:
name: Install Leiningen
command: |
sudo script/install-leiningen
- 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-java11-21.0.0 ]; then
curl -O -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0/graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
tar xzf graalvm-ce-java11-linux-aarch64-21.0.0.tar.gz
fi
- run:
name: Build binary
command: |
script/uberjar
script/compile
no_output_timeout: 30m
- run:
name: Run tests
command: |
script/test
script/run_lib_tests
- run:
name: Release
command: |
.circleci/script/release
- persist_to_workspace:
root: /tmp
paths:
- release
- save_cache:
paths:
- ~/.m2
- ~/graalvm-ce-java11-21.0.0
key: linux-aarch64-{{ 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 || true
mac: mac:
macos: macos:
xcode: "12.0.0" xcode: "12.0.0"
@ -336,6 +425,7 @@ workflows:
- linux - linux
- linux-static - linux-static
- mac - mac
- linux-aarch64
- deploy: - deploy:
filters: filters:
branches: branches:

View file

@ -17,12 +17,12 @@ fi
if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$CIRCLE_BRANCH" = "master" ]; then if [ -z "$CIRCLE_PULL_REQUEST" ] && [ "$CIRCLE_BRANCH" = "master" ]; then
echo "Building Docker image $image_name:$image_tag" echo "Building Docker image $image_name:$image_tag"
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin
unzip "/tmp/release/babashka-${image_tag}-linux-amd64.zip" tar zxvf "/tmp/release/babashka-${image_tag}-linux-amd64.tar.gz"
docker build -t "$image_name" -f Dockerfile.ci . docker build -t "$image_name" -f Dockerfile.ci .
docker tag "$image_name:$latest_tag" "$image_name:$image_tag" docker tag "$image_name:$latest_tag" "$image_name:$image_tag"
rm -f bb rm -f bb
if [[ $snapshot == "false" ]]; then if [[ $snapshot == "false" ]]; then
unzip "/tmp/release/babashka-${image_tag}-linux-static-amd64.zip" tar zxvf "/tmp/release/babashka-${image_tag}-linux-static-amd64.tar.gz"
docker build -t "$image_name:alpine" -f Dockerfile.alpine . docker build -t "$image_name:alpine" -f Dockerfile.alpine .
docker tag "$image_name:alpine" "$image_name:$image_tag-alpine" docker tag "$image_name:alpine" "$image_name:$image_tag-alpine"
fi fi

View file

@ -16,7 +16,7 @@
(curl/post slack-hook-url {:headers {"content-type" "application/json"} (curl/post slack-hook-url {:headers {"content-type" "application/json"}
:body json})))) :body json}))))
(def release-text (format "[%s - %s@%s]: https://%s-201467090-gh.circle-artifacts.com/0/release/babashka-%s-%s-amd64.zip" (def release-text (format "[%s - %s@%s]: https://%s-201467090-gh.circle-artifacts.com/0/release/babashka-%s-%s-amd64.tar.gz"
(System/getenv "BABASHKA_PLATFORM") (System/getenv "BABASHKA_PLATFORM")
(System/getenv "CIRCLE_BRANCH") (System/getenv "CIRCLE_BRANCH")
(System/getenv "CIRCLE_SHA1") (System/getenv "CIRCLE_SHA1")

View file

@ -11,9 +11,11 @@ cd /tmp/release
mkdir -p /tmp/bb_size mkdir -p /tmp/bb_size
./bb '(spit "/tmp/bb_size/size" (.length (io/file "bb")))' ./bb '(spit "/tmp/bb_size/size" (.length (io/file "bb")))'
## release binary as zip archive ## release binary as tar.gz archive
zip "babashka-$VERSION-$BABASHKA_PLATFORM-amd64.zip" bb # bbk arch=${BABASHKA_ARCH:-amd64}
tar zcvf "babashka-$VERSION-$BABASHKA_PLATFORM-$arch.tar.gz" bb # bbk
## cleanup ## cleanup

View file

@ -2,24 +2,126 @@
For a list of breaking changes, check [here](#breaking-changes). For a list of breaking changes, check [here](#breaking-changes).
## Unreleased ## 0.3.1
Babashka proper:
- Support `bb.edn` project config with `:paths` and `:deps`. See [docs](https://book.babashka.org/index.html#_bb_edn).
- Rewrite CLI arg parsing to to subcommand style invocations: `bb --uberjar` becomes `bb uberjar`
- Support fully qualified symbol in `--main` option [#758](https://github.com/babashka/babashka/issues/758). See [docs](https://book.babashka.org/index.html#_invoking_a_main_function ).
- Support new `doc` option to retrieve a docstring from the command line
Babashka.fs:
- Create target dir automatically in `copy-tree`
Babashka.nrepl:
- Implement `cider-nrepl` `info` / `lookup` op [#30](https://github.com/babashka/babashka.nrepl/issues/30) [(@brdloush)](https://github.com/brdloush)
Babashka.process:
- Support tokenizing single string [#39](https://github.com/babashka/process/issues/39)
- Support `:extra-env` option [#40](https://github.com/babashka/process/issues/40)
Deps.clj:
- Catch up with Clojure CLI 1.10.3.814 [#40](https://github.com/borkdude/deps.clj/issues/40)
Sci:
- Support new kwargs handling from 1.11.0 [#553](https://github.com/borkdude/sci/issues/553)
- Allow dynamic `:doc` on `def`/`defn` [#554](https://github.com/borkdude/sci/issues/554)
## 0.3.0
### New
- Linux support for AArch64 [#241](https://github.com/babashka/babashka/issues/241). This means you can now run babashka on Raspberry Pi 64bit and Chromebooks with ARM 64-bit processors!
A major thanks to [CircleCI](https://circleci.com/) for enabling AArch64 support
in the babashka organization and [GraalVM](http://graalvm.org/) for supporting this platform.
### Enhancements / fixes
- Fix `print-method` when writing to stdout [#667](https://github.com/babashka/babashka/issues/667)
- Fix interop with `System/out` [#754](https://github.com/babashka/babashka/issues/754)
- Support [version-clj](https://github.com/xsc/version-clj) v2.0.1 by adding `java.util.regex.Matcher` to the reflection config
- Distribute linux and macOS archives as `tar.gz`. The reason is that `unzip` is
not pre-installed on most unix-y systems. ([@grazfather](https://github.com/grazfather))
Babashka.fs:
- Fix globbing on Windows
- Fix Windows tests
- Fix issue with `copy-tree` when dest dir doesn't exist yet
Thanks [@lread](https://github.com/lread) for his help on fixing issues with Windows.
Sci:
- Support `:reload-all` [#552](https://github.com/borkdude/sci/issues/552)
- Narrow `reify` to just one class. See discussion in
[sci#549](https://github.com/borkdude/sci/issues/549).
- Add preliminary support for `proxy` (mainly to support pathom3 smart maps)
[sci#550](https://github.com/borkdude/sci/issues/550).
Thanks to [@wilkerlucio](https://github.com/wilkerlucio) and
[@GreshamDanielStephens](https://github.com/GreshamDanielStephens) for their
help and discussions.
## v0.2.13
### Enhancements / fixes
- Add more interfaces to be used with `reify` ([@wilkerlucio](https://github.com/wilkerlucio)) (mostly to support smart maps with [pathom3](https://github.com/wilkerlucio/pathom3))
Babashka.curl:
- Use `--data-binary` when sending files or streams [#35](https://github.com/babashka/babashka.curl/issues/35)
Babashka.fs:
- Add `create-link` and `split-paths` ([@eamonnsullivan](https://github.com/eamonnsullivan))
- Add `split-ext` and `extension` ([@kiramclean](https://github.com/kiramclean))
- Add `regular-file?`([@tekacs](https://github.com/tekacs))
- Globbing is always recursive but should not be [#18](https://github.com/babashka/fs/issues/18)
Sci:
- Allow combinations of interfaces and protocols in `reify` [#540](https://github.com/borkdude/sci/issues/540)
([@GreshamDanielStephens](https://github.com/GreshamDanielStephens))
- Fix metadata on non-constant map literal expression [#546](https://github.com/borkdude/sci/issues/546)
## 0.2.12
### Enhancements / fixes
- Fix false positive cyclic dep problem with doric lib [#741](https://github.com/babashka/babashka/issues/741)
## 0.2.11
### Enhancements / fixes ### Enhancements / fixes
- Use default `*print-right-margin*` value from `clojure.pprint` - Use default `*print-right-margin*` value from `clojure.pprint`
- Upgrade httpkit to 2.5.3 [#738](https://github.com/babashka/babashka/issues/738)
- Upgrade tools.cli to 1.0.206
- Add several classes to be used with `defprotocol` (`PersistentVector`, `PersistentHashSet`, ...)
- Support reifying `clojure.lang.IFn` and `clojure.lang.ILookup`
Sci: Sci:
- Detect cyclic load dependencies [#531](https://github.com/babashka/babashka/issues/531) - Detect cyclic load dependencies [#531](https://github.com/borkdude/sci/issues/531)
- Pick fn arity independent of written order [#532](https://github.com/babashka/babashka/issues/532) ([@GreshamDanielStephens](https://github.com/GreshamDanielStephens)) - Pick fn arity independent of written order [#532](https://github.com/borkdude/sci/issues/532) ([@GreshamDanielStephens](https://github.com/GreshamDanielStephens))
- `(instance? clojure.lang.IAtom 1)` returns `true` [#537](https://github.com/borkdude/sci/issues/537)
Babashka.fs: - Add `dissoc!`([@wilkerlucio](https://github.com/wilkerlucio))
- Add `force`
- Add `create-link` and `split-paths` - Fix `ns-unmap` on referred var [#539](https://github.com/borkdude/sci/issues/539)
Babashka.nrepl: Babashka.nrepl:
- Fix printing in lazy value [#36](https://github.com/babashka/babashka.nrepl/issues/36) - Fix printing in lazy value [#36](https://github.com/babashka/babashka.nrepl/issues/36)
- Update link in nREPL server message [#37](https://github.com/babashka/babashka.nrepl/issues/37)
## 0.2.10 ## 0.2.10
@ -44,11 +146,11 @@ Babashka.nrepl:
Sci: Sci:
- Fix error reporting in case of arity error [#518](https://github.com/babashka/babashka/issues/518) - Fix error reporting in case of arity error [#518](https://github.com/borkdude/sci/issues/518)
- Shadowing record field names in protocol functions [#513](https://github.com/babashka/babashka/issues/513) - Shadowing record field names in protocol functions [#513](https://github.com/borkdude/sci/issues/513)
- Fix destructuring in protocol method for record [#512](https://github.com/babashka/babashka/issues/512) - Fix destructuring in protocol method for record [#512](https://github.com/borkdude/sci/issues/512)
- Faster processing of maps, sets and vectors [#482](https://github.com/babashka/babashka/issues/482) - Faster processing of maps, sets and vectors [#482](https://github.com/borkdude/sci/issues/482)
- Prioritize current namespace vars in syntax quote [#509](https://github.com/babashka/babashka/issues/509) - Prioritize current namespace vars in syntax quote [#509](https://github.com/borkdude/sci/issues/509)
- Fix ns-publics to not include refers [#520](https://github.com/borkdude/sci/issues/520) - Fix ns-publics to not include refers [#520](https://github.com/borkdude/sci/issues/520)
- Add `refer-clojure` macro [#519](https://github.com/borkdude/sci/issues/519) - Add `refer-clojure` macro [#519](https://github.com/borkdude/sci/issues/519)

View file

@ -14,7 +14,7 @@ RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswit
RUN bb -e "(curl/get \"https://httpstat.us/200\")" # cURL http test RUN bb -e "(curl/get \"https://httpstat.us/200\")" # cURL http test
RUN bb -e "(require '[org.httpkit.client :as http]) (when-let [error (:error @(http/get \"https://httpstat.us/200\"))] (throw error))" # JVM http test RUN bb -e "(require '[org.httpkit.client :as http]) (when-let [error (:error @(http/get \"https://httpstat.us/200\"))] (throw error))" # JVM http test
RUN bb -e "(.length \"Hello, Babashka\")" # Java interop test RUN bb -e "(.length \"Hello, Babashka\")" # Java interop test
RUN bb -e "(require '[babashka.pods :as pods]) (pods/load-pod 'org.babashka/sqlite3 \"0.0.1\") (require '[pod.babashka.sqlite3 :as sqlite]) (sqlite/execute! \"/tmp/foo.db\" [\"SELECT 1 + 1\"])" # Pod test RUN bb -e "(require '[babashka.pods :as pods]) (pods/load-pod 'org.babashka/go-sqlite3 \"0.0.1\") (require '[pod.babashka.go-sqlite3 :as sqlite]) (sqlite/execute! \"/tmp/foo.db\" [\"SELECT 1 + 1\"])" # Pod test
FROM alpine:3 FROM alpine:3

View file

@ -5,8 +5,6 @@
[![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/babashka/babashka.svg)](https://clojars.org/babashka/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/babashka/babashka.svg)](https://clojars.org/babashka/babashka)
[![twitter](https://img.shields.io/badge/twitter-%23babashka-blue)](https://twitter.com/search?q=%23babashka&src=typed_query&f=live) [![twitter](https://img.shields.io/badge/twitter-%23babashka-blue)](https://twitter.com/search?q=%23babashka&src=typed_query&f=live)
A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash.
<blockquote class="twitter-tweet" data-lang="en"> <blockquote class="twitter-tweet" data-lang="en">
<p lang="en" dir="ltr">Life's too short to remember how to write Bash code. I feel liberated.</p> <p lang="en" dir="ltr">Life's too short to remember how to write Bash code. I feel liberated.</p>
&mdash; &mdash;
@ -15,8 +13,9 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas
## Introduction ## Introduction
The main idea behind babashka is to leverage Clojure in places where you would Babashka is a native Clojure interpreter for scripting with fast startup. Its
be using bash otherwise. main goal is to leverage Clojure in places where you would be using bash
otherwise.
As one user described it: As one user described it:

@ -1 +1 @@
Subproject commit 33bfad1b844927966a2a681d3e73e4d2a8eae54b Subproject commit e1f33ffa22728553bf2242db5e2a4ca349fab04b

@ -1 +1 @@
Subproject commit 15ff3c1b43bfc30e806336547bdb0918f9e2521c Subproject commit 3a790c3d378ddda190d650202cefba9b9930176c

@ -1 +1 @@
Subproject commit 0b70844983bf23fff4c2991dadb3fd14c4102b27 Subproject commit ca0e98fcefb916c6c0e6fdac73800395b8923af8

View file

@ -13,13 +13,13 @@
"depstar/src" "process/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources" "deps.clj/src" "deps.clj/resources"
"resources" "sci/resources"], "resources" "sci/resources"],
:deps {org.clojure/clojure {:mvn/version "1.10.2"}, :deps {org.clojure/clojure {:mvn/version "1.10.3"},
borkdude/sci {:local/root "sci"} borkdude/sci {:local/root "sci"}
babashka/babasha.curl {:local/root "babashka.curl"} babashka/babasha.curl {:local/root "babashka.curl"}
babashka/fs {:local/root "fs"} babashka/fs {:local/root "fs"}
borkdude/graal.locking {:mvn/version "0.0.2"}, borkdude/graal.locking {:mvn/version "0.0.2"},
org.clojure/core.async {:mvn/version "1.3.610"}, org.clojure/core.async {:mvn/version "1.3.610"},
org.clojure/tools.cli {:mvn/version "1.0.194"}, org.clojure/tools.cli {:mvn/version "1.0.206"},
org.clojure/data.csv {:mvn/version "1.0.0"}, org.clojure/data.csv {:mvn/version "1.0.0"},
cheshire/cheshire {:mvn/version "5.10.0"} cheshire/cheshire {:mvn/version "5.10.0"}
org.clojure/data.xml {:mvn/version "0.2.0-alpha6"} org.clojure/data.xml {:mvn/version "0.2.0-alpha6"}
@ -31,13 +31,12 @@
org.postgresql/postgresql {:mvn/version "42.2.18"} org.postgresql/postgresql {:mvn/version "42.2.18"}
org.hsqldb/hsqldb {:mvn/version "2.5.1"} org.hsqldb/hsqldb {:mvn/version "2.5.1"}
datascript/datascript {:mvn/version "1.0.1"} datascript/datascript {:mvn/version "1.0.1"}
http-kit/http-kit {:mvn/version "2.5.1"} http-kit/http-kit {:mvn/version "2.5.3"}
babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"} babashka/clojure-lanterna {:mvn/version "0.9.8-SNAPSHOT"}
org.clojure/math.combinatorics {:mvn/version "0.1.6"}
org.clojure/core.match {:mvn/version "1.0.0"} org.clojure/core.match {:mvn/version "1.0.0"}
hiccup/hiccup {:mvn/version "2.0.0-alpha2"} hiccup/hiccup {:mvn/version "2.0.0-alpha2"}
metosin/malli {:mvn/version "0.3.0-SNAPSHOT"}} metosin/malli {:mvn/version "0.3.0-SNAPSHOT"}}
:aliases {:main :aliases {:babashka/dev
{:main-opts ["-m" "babashka.main"]} {:main-opts ["-m" "babashka.main"]}
:profile :profile
{:extra-deps {:extra-deps
@ -72,9 +71,12 @@
honeysql/honeysql {:mvn/version "1.0.444"} honeysql/honeysql {:mvn/version "1.0.444"}
minimallist/minimallist {:mvn/version "0.0.6"} minimallist/minimallist {:mvn/version "0.0.6"}
circleci/bond {:mvn/version "0.4.0"} circleci/bond {:mvn/version "0.4.0"}
version-clj/version-clj {:mvn/version "0.1.2"} version-clj/version-clj {:mvn/version "2.0.1"}
gaka/gaka {:mvn/version "0.3.0"} gaka/gaka {:mvn/version "0.3.0"}
failjure/failjure {:mvn/version "2.1.1"}}} failjure/failjure {:mvn/version "2.1.1"}}
:classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil
org.clojure/core.specs.alpha nil}}
:clj-nvd :clj-nvd
{:extra-deps {clj-nvd/clj-nvd {:git/url "https://github.com/miikka/clj-nvd.git" {:extra-deps {clj-nvd/clj-nvd {:git/url "https://github.com/miikka/clj-nvd.git"
:sha "f2ec98699e057a379baf170cb49cf7ad76874a70"}} :sha "f2ec98699e057a379baf170cb49cf7ad76874a70"}}

View file

@ -39,7 +39,7 @@ $ git clone https://github.com/babashka/babashka --recursive
To update later on: To update later on:
``` shellsession ``` shellsession
$ git submodule update --recursive $ git submodule update --init --recursive
``` ```
## Build ## Build

View file

@ -5,10 +5,19 @@ you have anything to add. Also see
[#babashka](https://twitter.com/hashtag/babashka?src=hashtag_click&f=live) on [#babashka](https://twitter.com/hashtag/babashka?src=hashtag_click&f=live) on
Twitter. Twitter.
## 2021-03
- A `python -m http.server` [replacement in babashka](https://gist.github.com/holyjak/36c6284c047ffb7573e8a34399de27d8)
- A [PR](https://github.com/ring-clojure/ring-codec/issues/26) to make `ring-codec` compatible with babashka
- The [stuartsierra/component](https://github.com/stuartsierra/component) library [seems to work with babashka](https://github.com/babashka/babashka/issues/742)
- [pathom3](https://pathom3.wsscode.com/docs/tutorials/babashka/) works with babashka!
## 2021-02 ## 2021-02
- Babashka 0.2.9 released - Babashka 0.2.9 - 0.2.12 released
- [babashka.fs](https://github.com/babashka/fs): utility library for dealing with files (based on java.nio). Bundled with bb 0.2.9. - [babashka.fs](https://github.com/babashka/fs): utility library for dealing with files (based on java.nio). Bundled with bb 0.2.9.
- New [Youtube channel](https://www.youtube.com/channel/UCRCl_R1ihLJt7IOgICdb9Lw) with babashka related videos
- MS SQL support for the [babashka sql pods](https://github.com/babashka/babashka-sql-pods/)
- [Clojure like its PHP](https://eccentric-j.com/blog/clojure-like-its-php.html): run babashka scripts as CGI scripts - [Clojure like its PHP](https://eccentric-j.com/blog/clojure-like-its-php.html): run babashka scripts as CGI scripts
- [Automating Video Edits with Clojure and ffmpeg](https://youtu.be/Tmgy57R9HZM) by Adam James - [Automating Video Edits with Clojure and ffmpeg](https://youtu.be/Tmgy57R9HZM) by Adam James
@ -19,12 +28,20 @@ Twitter.
lein imitation script built on deps.edn lein imitation script built on deps.edn
- [failjure](https://github.com/adambard/failjure) works with babashka. - [failjure](https://github.com/adambard/failjure) works with babashka.
- A [script](https://gist.github.com/borkdude/58f099b2694d206e6eec18daedc5077b) to solve our mono-repo problem with deps.edn at work. - A [script](https://gist.github.com/borkdude/58f099b2694d206e6eec18daedc5077b) to solve our mono-repo problem with deps.edn at work.
- [Single-script vega-lite plotter](https://gist.github.com/vdikan/6b6063d6e1b00a3cd79bc7b3ce3853d6/)
- [Find vars with the clj-kondo pod](https://gist.github.com/borkdude/841d85d5ad04c517337166b3928697bd). Also see [video](https://youtu.be/TvBmtGS0KJE).
- [Another setup babashka Github action](https://github.com/marketplace/actions/setup-babashka)
- [AWS Lambda + babashka + minimal container image](https://gist.github.com/lukaszkorecki/a1fe27bf08f9b98e9def9da4bcb3264e)
- [football script](https://gist.github.com/mmzsource/a732950aa43d19c5a9b63bbb7f20b7eb)
- [ffclj](https://github.com/luissantos/ffclj): Clojure ffmpeg wrapper
- [clj-lineart](https://github.com/eccentric-j/clj-lineart): Generative line art from a clojure-cgi script
- [bunpack](https://github.com/robertfw/bunpack): remembers how to unpack things, so you don't have to
- A script to download deps for [all `deps.edn` aliases](https://github.com/babashka/babashka/blob/master/examples/download-aliases.clj)
## 2021-01 ## 2021-01
Babashka [0.2.8](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v028) released. This includes new libraries: hiccup, core.match and clojure.test.check. - Babashka [0.2.8](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v028) released. This includes new libraries: hiccup, core.match and clojure.test.check.
- On 27th of February, Michiel (a.k.a. @borkdude) will do a talk about babashka at the [2021 GraalVM workshop](https://graalworkshop.github.io/2021/).
On 27th of February, Michiel (a.k.a. @borkdude) will do a talk about babashka at the [2021 GraalVM workshop](https://graalworkshop.github.io/2021/).
- First release of the [aws pod](https://github.com/babashka/pod-babashka-aws). - First release of the [aws pod](https://github.com/babashka/pod-babashka-aws).
- A [script](https://gist.github.com/borkdude/ba372c8cee311e31020b04063d88e1be) to print API breakage warnings. - A [script](https://gist.github.com/borkdude/ba372c8cee311e31020b04063d88e1be) to print API breakage warnings.
@ -38,16 +55,16 @@ On 27th of February, Michiel (a.k.a. @borkdude) will do a talk about babashka at
## 2020-12 ## 2020-12
A new babashka talk: [Babashka and sci - A new babashka talk: [Babashka and sci
internals](https://youtu.be/pgNp4Lk3gf0). Also see internals](https://youtu.be/pgNp4Lk3gf0). Also see
[slides](https://speakerdeck.com/babashka/babashka-and-sci-internals-at-london-clojurians-december-2020) [slides](https://speakerdeck.com/babashka/babashka-and-sci-internals-at-london-clojurians-december-2020)
and [REPL and [REPL
session](https://gist.github.com/borkdude/66a4d844668e12ae1a8277af10d6cc4b). session](https://gist.github.com/borkdude/66a4d844668e12ae1a8277af10d6cc4b).
Babashka 0.2.6 released. See [release - Babashka 0.2.6 released. See [release
notes](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v026). notes](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v026).
Babashka 0.2.5 released. See [release - Babashka 0.2.5 released. See [release
notes](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v025). notes](https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v025).
- First release of the [sqlite pod](https://github.com/babashka/pod-babashka-sqlite3) - First release of the [sqlite pod](https://github.com/babashka/pod-babashka-sqlite3)

View file

@ -34,6 +34,8 @@ The following libraries and projects are known to work with babashka.
- [environ](#environ) - [environ](#environ)
- [gaka](#gaka) - [gaka](#gaka)
- [failjure](#failjure) - [failjure](#failjure)
- [pretty](#pretty)
- [clojure-term-colors](#clojure-term-colors)
- [Pods](#pods) - [Pods](#pods)
- [Projects](#projects-1) - [Projects](#projects-1)
- [babashka-test-action](#babashka-test-action) - [babashka-test-action](#babashka-test-action)
@ -450,6 +452,42 @@ Working with failed computations in Clojure.
(f/fail "foo") (f/fail "foo")
``` ```
### [pretty](https://github.com/AvisoNovate/pretty)
The `io.aviso.ansi` namespace provides ANSI font and background color support.
``` clojure
(require '[babashka.deps :as deps])
(deps/add-deps
'{:deps {io.aviso/pretty {:mvn/version "0.1.36"}}})
(require '[io.aviso.ansi :as ansi])
(println
(str "The following text will be "
ansi/bold-red-font "bold and red "
ansi/reset-font "but this text will not."))
```
### [clojure-term-colors](https://github.com/trhura/clojure-term-colors)
Clojure ASCII color formatting for terminal output.
``` clojure
(require '[babashka.deps :as deps])
(deps/add-deps
'{:deps {clojure-term-colors/clojure-term-colors {:mvn/version "0.1.0"}}})
(require '[clojure.term.colors :as c])
(println
(c/yellow "Yellow")
(c/red "Red")
"No color")
```
## Pods ## Pods
[Babashka pods](https://github.com/babashka/babashka.pods) are programs that can [Babashka pods](https://github.com/babashka/babashka.pods) are programs that can

View file

@ -1,5 +1,37 @@
# Examples # Examples
- [Examples](#examples)
- [Delete a list of files returned by a Unix command](#delete-a-list-of-files-returned-by-a-unix-command)
- [Calculate aggregate size of directory](#calculate-aggregate-size-of-directory)
- [Shuffle the lines of a file](#shuffle-the-lines-of-a-file)
- [Fetch latest Github release tag](#fetch-latest-github-release-tag)
- [Generate deps.edn entry for a gitlib](#generate-depsedn-entry-for-a-gitlib)
- [View download statistics from Clojars](#view-download-statistics-from-clojars)
- [Portable tree command](#portable-tree-command)
- [List outdated maven dependencies](#list-outdated-maven-dependencies)
- [Convert project.clj to deps.edn](#convert-projectclj-to-depsedn)
- [Print current time in California](#print-current-time-in-california)
- [Tiny http server](#tiny-http-server)
- [Print random docstring](#print-random-docstring)
- [Cryptographic hash](#cryptographic-hash)
- [Package script as Docker image](#package-script-as-docker-image)
- [Extract single file from zip](#extract-single-file-from-zip)
- [Note taking app](#note-taking-app)
- [which](#which)
- [pom.xml version](#pomxml-version)
- [Whatsapp frequencies](#whatsapp-frequencies)
- [Find unused vars](#find-unused-vars)
- [List contents of jar file](#list-contents-of-jar-file)
- [Invoke vim inside a script](#invoke-vim-inside-a-script)
- [Portal](#portal)
- [Image viewer](#image-viewer)
- [File server](#file-server)
- [Torrent viewer](#torrent-viewer)
- [cprop.clj](#cpropclj)
- [fzf](#fzf)
- [digitalocean-ping.clj](#digitalocean-pingclj)
- [download-aliases.clj](#download-aliasesclj)
Here's a gallery of useful examples. Do you have a useful example? PR welcome! Here's a gallery of useful examples. Do you have a useful example? PR welcome!
## Delete a list of files returned by a Unix command ## Delete a list of files returned by a Unix command
@ -161,7 +193,9 @@ See [examples/pst.clj](https://github.com/babashka/babashka/blob/master/examples
## Tiny http server ## Tiny http server
See [examples/http_server.clj](https://github.com/babashka/babashka/blob/master/examples/http_server.clj) This implements an http server from scratch. Note that babashka comes with `org.httpkit.server` now, so you don't need to build an http server from scratch anymore.
See [examples/http_server_from_scratch.clj](https://github.com/babashka/babashka/blob/master/examples/http_server_from_scratch.clj)
Original by [@souenzzo](https://gist.github.com/souenzzo/a959a4c5b8c0c90df76fe33bb7dfe201) Original by [@souenzzo](https://gist.github.com/souenzzo/a959a4c5b8c0c90df76fe33bb7dfe201)
@ -330,10 +364,22 @@ Opens browser window and lets user navigate through images of all sub-directorie
Example usage: Example usage:
``` shell ``` shell
$ examples/image_viewer.clj $ examples/image-viewer.clj
``` ```
See [image_viewer.clj](image_viewer.clj). See [image-viewer.clj](image-viewer.clj).
## File server
Opens browser window and lets user navigate through filesystem.
Example usage:
``` shell
$ examples/file-server.clj
```
See [file-server.clj](file-server.clj).
## Torrent viewer ## Torrent viewer
@ -370,18 +416,6 @@ Example usage:
$ cat src/babashka/main.clj | bb examples/fzf.clj $ cat src/babashka/main.clj | bb examples/fzf.clj
``` ```
## [rofi](rofi.clj)
Invoke [rofi](https://github.com/davatorium/rofi), a type-to-filter menu on linux, from babashka.
See [rofi.clj](rofi.clj)
Example usage:
``` shell
$ cat src/babashka/main.clj | bb examples/rofi.clj
```
## [digitalocean-ping.clj](digitalocean-ping.clj) ## [digitalocean-ping.clj](digitalocean-ping.clj)
The script allows to define which DigitalOcean cloud datacenter (region) has best network performance (ping latency). The script allows to define which DigitalOcean cloud datacenter (region) has best network performance (ping latency).

196
examples/file-server.clj Executable file
View file

@ -0,0 +1,196 @@
#!/usr/bin/env bb
#_" -*- mode: clojure; -*-"
;; Source: https://gist.github.com/holyjak/36c6284c047ffb7573e8a34399de27d8
;; Based on https://github.com/babashka/babashka/blob/master/examples/image_viewer.clj
(ns file-server
(:require [babashka.fs :as fs]
[clojure.java.browse :as browse]
[clojure.string :as str]
[clojure.tools.cli :refer [parse-opts]]
[hiccup2.core :as html]
[org.httpkit.server :as server])
(:import [java.net URLDecoder URLEncoder]))
(def cli-options [["-p" "--port PORT" "Port for HTTP server" :default 8090 :parse-fn #(Integer/parseInt %)]
["-d" "--dir DIR" "Directory to serve files from" :default "."]
["-h" "--help" "Print usage info"]])
(def parsed-args (parse-opts *command-line-args* cli-options))
(def opts (:options parsed-args))
(cond
(:help opts)
(do (println "Start a http server for static files in the given dir. Usage:\n" (:summary parsed-args))
(System/exit 0))
(:errors parsed-args)
(do (println "Invalid arguments:\n" (str/join "\n" (:errors parsed-args)))
(System/exit 1))
:else
:continue)
(def port (:port opts))
(def dir (fs/path (:dir opts)))
(assert (fs/directory? dir) (str "The given dir `" dir "` is not a directory."))
;; A simple mime type utility from https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/util/mime_type.clj
(def ^{:doc "A map of file extensions to mime-types."}
default-mime-types
{"7z" "application/x-7z-compressed"
"aac" "audio/aac"
"ai" "application/postscript"
"appcache" "text/cache-manifest"
"asc" "text/plain"
"atom" "application/atom+xml"
"avi" "video/x-msvideo"
"bin" "application/octet-stream"
"bmp" "image/bmp"
"bz2" "application/x-bzip"
"class" "application/octet-stream"
"cer" "application/pkix-cert"
"crl" "application/pkix-crl"
"crt" "application/x-x509-ca-cert"
"css" "text/css"
"csv" "text/csv"
"deb" "application/x-deb"
"dart" "application/dart"
"dll" "application/octet-stream"
"dmg" "application/octet-stream"
"dms" "application/octet-stream"
"doc" "application/msword"
"dvi" "application/x-dvi"
"edn" "application/edn"
"eot" "application/vnd.ms-fontobject"
"eps" "application/postscript"
"etx" "text/x-setext"
"exe" "application/octet-stream"
"flv" "video/x-flv"
"flac" "audio/flac"
"gif" "image/gif"
"gz" "application/gzip"
"htm" "text/html"
"html" "text/html"
"ico" "image/x-icon"
"iso" "application/x-iso9660-image"
"jar" "application/java-archive"
"jpe" "image/jpeg"
"jpeg" "image/jpeg"
"jpg" "image/jpeg"
"js" "text/javascript"
"json" "application/json"
"lha" "application/octet-stream"
"lzh" "application/octet-stream"
"mov" "video/quicktime"
"m3u8" "application/x-mpegurl"
"m4v" "video/mp4"
"mjs" "text/javascript"
"mp3" "audio/mpeg"
"mp4" "video/mp4"
"mpd" "application/dash+xml"
"mpe" "video/mpeg"
"mpeg" "video/mpeg"
"mpg" "video/mpeg"
"oga" "audio/ogg"
"ogg" "audio/ogg"
"ogv" "video/ogg"
"pbm" "image/x-portable-bitmap"
"pdf" "application/pdf"
"pgm" "image/x-portable-graymap"
"png" "image/png"
"pnm" "image/x-portable-anymap"
"ppm" "image/x-portable-pixmap"
"ppt" "application/vnd.ms-powerpoint"
"ps" "application/postscript"
"qt" "video/quicktime"
"rar" "application/x-rar-compressed"
"ras" "image/x-cmu-raster"
"rb" "text/plain"
"rd" "text/plain"
"rss" "application/rss+xml"
"rtf" "application/rtf"
"sgm" "text/sgml"
"sgml" "text/sgml"
"svg" "image/svg+xml"
"swf" "application/x-shockwave-flash"
"tar" "application/x-tar"
"tif" "image/tiff"
"tiff" "image/tiff"
"ts" "video/mp2t"
"ttf" "font/ttf"
"txt" "text/plain"
"webm" "video/webm"
"wmv" "video/x-ms-wmv"
"woff" "font/woff"
"woff2" "font/woff2"
"xbm" "image/x-xbitmap"
"xls" "application/vnd.ms-excel"
"xml" "text/xml"
"xpm" "image/x-xpixmap"
"xwd" "image/x-xwindowdump"
"zip" "application/zip"})
;; https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/util/mime_type.clj
(defn- filename-ext
"Returns the file extension of a filename or filepath."
[filename]
(if-let [ext (second (re-find #"\.([^./\\]+)$" filename))]
(str/lower-case ext)))
;; https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/util/mime_type.clj
(defn ext-mime-type
"Get the mimetype from the filename extension. Takes an optional map of
extensions to mimetypes that overrides values in the default-mime-types map."
([filename]
(ext-mime-type filename {}))
([filename mime-types]
(let [mime-types (merge default-mime-types mime-types)]
(mime-types (filename-ext filename)))))
(defn index [f]
(let [files (map #(str (.relativize dir %))
(fs/list-dir f))]
{:body (-> [:html
[:head
[:meta {:charset "UTF-8"}]
[:title (str "Index of `" f "`")]]
[:body
[:h1 "Index of " [:code (str f)]]
[:ul
(for [child files]
[:li [:a {:href (URLEncoder/encode (str child))} child
(when (fs/directory? (fs/path dir child)) "/")]])]
[:hr]
[:footer {:style {"text-aling" "center"}} "Served by http-server.clj"]]]
html/html
str)}))
(defn body [path]
{:headers {"Content-Type" (ext-mime-type (fs/file-name path))}
:body (fs/file path)})
(server/run-server
(fn [{:keys [:uri]}]
(let [f (fs/path dir (str/replace-first (URLDecoder/decode uri) #"^/" ""))
index-file (fs/path f "index.html")]
(cond
(and (fs/directory? f) (fs/readable? index-file))
(body index-file)
(fs/directory? f)
(index f)
(fs/readable? f)
(body f)
:else
{:status 404 :body (str "Not found `" f "` in " dir)})))
{:port port})
(println "Starting http server at " port "for" (str dir))
(browse/browse-url (format "http://localhost:%s/" port))
@(promise)

View file

@ -1,10 +1,13 @@
#!/usr/bin/env bb #!/usr/bin/env bb
;; This example creates a file serving web server ;; This example creates a file serving web server from scratch.
;; It accepts a single connection from a browser and serves content to the connected browser ;; It accepts a single connection from a browser and serves content to the connected browser
;; after the connection times out, this script will serve no more. ;; after the connection times out, this script will serve no more.
;; Also see notes.clj for another web app example. ;; Also see notes.clj for another web app example.
;; Note that babashka comes with org.httpkit.server now, so you don't need to
;; build an http server from scratch anymore. We leave this script here for educational purposes.
(import (java.net ServerSocket)) (import (java.net ServerSocket))
(require '[clojure.java.io :as io] (require '[clojure.java.io :as io]
'[clojure.string :as string]) '[clojure.string :as string])

View file

@ -1,8 +1,9 @@
#!/usr/bin/env bb #!/usr/bin/env bb
(import (java.net ServerSocket))
(require '[clojure.java.io :as io] (require '[clojure.java.io :as io]
'[clojure.string :as str]) '[clojure.pprint :refer [pprint]]
'[clojure.string :as str]
'[org.httpkit.server :as server])
(def debug? true) (def debug? true)
(def user "admin") (def user "admin")
@ -35,43 +36,23 @@
(str/join " " (map html v)) (str/join " " (map html v))
:else (str 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 ;; the home page
(defn home-response [out session-id] (defn home-response [session-id]
(let [body (str {:status 200
"<!DOCTYPE html>\n" :headers {"Set-Cookie" (str "notes-id=" session-id)}
(html :body (str
[:html "<!DOCTYPE html>\n"
[:head (html
[:title "Notes"]] [:html
[:body [:head
[:h1 "Notes"] [:title "Notes"]]
[:pre (when (.exists notes-file) [:body
(slurp notes-file))] [:h1 "Notes"]
[:form {:action "/" :method "post"} [:pre (when (.exists notes-file)
[:input {:type "text" :name "note"}] (slurp notes-file))]
[:input {:type "submit" :value "Submit"}]]]]))] [:form {:action "/" :method "post"}
(write-response out session-id "200 OK" nil body))) [:input {:type "text" :name "note"}]
[:input {:type "submit" :value "Submit"}]]]]))})
(defn basic-auth-response [out session-id]
(write-response out session-id
"401 Unauthorized"
["WWW-Authenticate: Basic realm=\"notes\""]
nil))
(def known-sessions (def known-sessions
(atom #{})) (atom #{}))
@ -81,67 +62,54 @@
(swap! known-sessions conj uuid) (swap! known-sessions conj uuid)
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 (def authenticated-sessions
(atom #{})) (atom #{}))
(defn authenticate! [session-id headers] (defn authenticate! [session-id headers]
(or (contains? @authenticated-sessions session-id) (or (contains? @authenticated-sessions session-id)
(when (some #(= % (str "Authorization: Basic " base64)) headers) (when (= (headers "authorization") (str "Basic " base64))
(swap! authenticated-sessions conj session-id) (swap! authenticated-sessions conj session-id)
true))) true)))
(defn parse-session-id [cookie]
(when cookie
(when-let [notes-id (first (filter #(str/starts-with? % "notes-id")
(str/split cookie #"; ")))]
(str/replace notes-id "notes-id=" ""))))
(defn basic-auth-response [session-id]
{:status 401
:headers {"WWW-Authenticate" "Basic realm=\"notes\""
"Set-Cookie" (str "notes-id=" session-id)}})
;; run the server ;; run the server
(with-open [server-socket (let [s (new ServerSocket 8080)] (defn handler [req]
(println "Server started on port 8080.") (when debug?
s)] (println "Request:")
(loop [] (pprint req))
(let [client-socket (.accept server-socket)] (let [body (some-> req :body slurp java.net.URLDecoder/decode)
(future session-id (parse-session-id (get-in req [:headers "cookie"]))
(with-open [conn client-socket] _ (when (and debug? body)
(try (println "Request body:" body))
(let [out (io/writer (.getOutputStream conn)) response (cond
is (.getInputStream conn) ;; if we didn't see this session before, we want the user to
in (io/reader is) ;; re-authenticate
[_req & headers :as response] (not (contains? @known-sessions session-id))
(loop [headers []] (basic-auth-response (new-session!))
(let [line (.readLine in)]
(if (str/blank? line) (not (authenticate! session-id (:headers req)))
headers (basic-auth-response session-id)
(recur (conj headers line)))))
session-id (get-session-id headers) :else (do (when-not (str/blank? body)
form-data (let [sb (StringBuilder.)] (let [note (str/replace body "note=" "")]
(loop [] (write-note! note)))
(when (.ready in) (home-response session-id)))]
(.append sb (char (.read in))) (when debug?
(recur))) (println "Response:")
(-> (str sb) (pprint (dissoc response :body))
(java.net.URLDecoder/decode))) (println))
_ (when debug? (println (str/join "\n" response))) response))
_ (when-not (str/blank? form-data)
(when debug? (println form-data)) (server/run-server handler {:port 8080})
(let [note (str/replace form-data "note=" "")] (println "Server started on port 8080.")
(write-note! note))) @(promise) ;; wait until SIGINT
_ (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)))

View file

@ -1,12 +0,0 @@
(require '[babashka.process :as p])
(defn rofi [s]
(let [proc (p/process
["rofi" "-i" "-dmenu" "-mesg" "Select" "-sync" "-p" "*"]
{:in s :err :inherit
:out :string})]
(:out @proc)))
(rofi (slurp *in*))
;; `echo "hi\nthere\nclj" | bb examples/rofi.clj`

2
fs

@ -1 +1 @@
Subproject commit caa1cb383329c353114ae24954c52b9d6fa038ea Subproject commit 19c03977282bd63a3ecfd3e6a261a433aa9e8745

32
install
View file

@ -64,25 +64,41 @@ case "$(uname -s)" in
Darwin*) platform=macos;; Darwin*) platform=macos;;
esac esac
download_url="https://github.com/babashka/babashka/releases/download/v$version/babashka-$version-$platform-amd64.zip" case "$(uname -m)" in
aarch64) arch=aarch64;;
esac
arch=${arch:-amd64}
# Ugly ugly conversion of version to a comparable number
IFS='.' read -ra VER <<< "$version"
vernum=$(printf "%03d%03d%03d" "${VER[0]}" "${VER[1]}" "${VER[2]}")
if [[ $vernum -le 000002013 ]]; then
ext="zip"
util="$(which unzip) -qqo"
else
ext="tar.gz"
util="$(which tar) -zxf"
fi
download_url="https://github.com/babashka/babashka/releases/download/v$version/babashka-$version-$platform-$arch."$ext
mkdir -p "$download_dir" mkdir -p "$download_dir"
cd "$download_dir" cd "$download_dir"
echo -e "Downloading $download_url to $download_dir" echo -e "Downloading $download_url to $download_dir"
rm -rf "babashka-$version-$platform-amd64.zip" rm -rf "babashka-$version-$platform-$arch."$ext
rm -rf "bb" rm -rf "bb"
curl -o "babashka-$version-$platform-amd64.zip" -sL "https://github.com/babashka/babashka/releases/download/v$version/babashka-$version-$platform-amd64.zip" curl -o "babashka-$version-$platform-$arch."$ext -sL $download_url
unzip -qqo "babashka-$version-$platform-amd64.zip" $util "babashka-$version-$platform-$arch."$ext
rm "babashka-$version-$platform-amd64.zip" rm "babashka-$version-$platform-$arch."$ext
if [ "$download_dir" != "$install_dir" ] if [ "$download_dir" != "$install_dir" ]
then then
mkdir -p "$install_dir" mkdir -p "$install_dir"
cd "$install_dir" if [ -f "$install_dir/bb" ]; then
if [ -f bb ]; then
echo "Moving $install_dir/bb to $install_dir/bb.old" echo "Moving $install_dir/bb to $install_dir/bb.old"
fi fi
mv -f "$download_dir/bb" "$PWD/bb" mv -f "$download_dir/bb" "$install_dir/bb"
fi fi
echo "Successfully installed bb in $install_dir" echo "Successfully installed bb in $install_dir"

2
pods

@ -1 +1 @@
Subproject commit 0bffce3573d0361cf2592d65cefc8a4048454ff9 Subproject commit 82aa3627106181a0ad58c289cd45129603e4fa24

@ -1 +1 @@
Subproject commit f5b531f706fd2b3cfba93c15411d3308e25b5917 Subproject commit 692195db27fe411b65e24dbacec75c9f4721a486

View file

@ -17,12 +17,11 @@
:dependencies [[org.clojure/clojure "1.10.2"] :dependencies [[org.clojure/clojure "1.10.2"]
[borkdude/edamame "0.0.11-alpha.29"] [borkdude/edamame "0.0.11-alpha.29"]
[borkdude/graal.locking "0.0.2"] [borkdude/graal.locking "0.0.2"]
[org.clojure/tools.cli "1.0.194"] [org.clojure/tools.cli "1.0.206"]
[cheshire "5.10.0"] [cheshire "5.10.0"]
[nrepl/bencode "1.1.0"] [nrepl/bencode "1.1.0"]
[borkdude/sci.impl.reflector "0.0.1"] [borkdude/sci.impl.reflector "0.0.1"]
[org.clojure/test.check "1.1.0"] [org.clojure/test.check "1.1.0"]]
[org.clojure/math.combinatorics "0.1.6"]]
:profiles {:feature/xml {:source-paths ["feature-xml"] :profiles {:feature/xml {:source-paths ["feature-xml"]
:dependencies [[org.clojure/data.xml "0.2.0-alpha6"]]} :dependencies [[org.clojure/data.xml "0.2.0-alpha6"]]}
:feature/yaml {:source-paths ["feature-yaml"] :feature/yaml {:source-paths ["feature-yaml"]
@ -42,9 +41,9 @@
:feature/datascript {:source-paths ["feature-datascript"] :feature/datascript {:source-paths ["feature-datascript"]
:dependencies [[datascript "1.0.1"]]} :dependencies [[datascript "1.0.1"]]}
:feature/httpkit-client {:source-paths ["feature-httpkit-client"] :feature/httpkit-client {:source-paths ["feature-httpkit-client"]
:dependencies [[http-kit "2.5.1"]]} :dependencies [[http-kit "2.5.3"]]}
:feature/httpkit-server {:source-paths ["feature-httpkit-server"] :feature/httpkit-server {:source-paths ["feature-httpkit-server"]
:dependencies [[http-kit "2.5.1"]]} :dependencies [[http-kit "2.5.3"]]}
:feature/lanterna {:source-paths ["feature-lanterna"] :feature/lanterna {:source-paths ["feature-lanterna"]
:dependencies [[babashka/clojure-lanterna "0.9.8-SNAPSHOT"]]} :dependencies [[babashka/clojure-lanterna "0.9.8-SNAPSHOT"]]}
:feature/core-match {:source-paths ["feature-core-match"] :feature/core-match {:source-paths ["feature-core-match"]
@ -70,8 +69,7 @@
:feature/hiccup :feature/hiccup
:feature/test-check :feature/test-check
:feature/spec-alpha :feature/spec-alpha
{:dependencies [[clj-commons/conch "0.9.2"] {:dependencies [[com.clojure-goes-fast/clj-async-profiler "0.4.1"]
[com.clojure-goes-fast/clj-async-profiler "0.4.1"]
[com.opentable.components/otj-pg-embedded "0.13.3"]]}] [com.opentable.components/otj-pg-embedded "0.13.3"]]}]
:uberjar {:global-vars {*assert* false} :uberjar {:global-vars {*assert* false}
:jvm-opts ["-Dclojure.compiler.direct-linking=true" :jvm-opts ["-Dclojure.compiler.direct-linking=true"

View file

@ -1 +1 @@
0.2.10 0.3.1

View file

@ -1 +1 @@
0.2.11-SNAPSHOT 0.3.2-SNAPSHOT

2
sci

@ -1 +1 @@
Subproject commit 043f5e60d674f5aeee0866e427cef58812ad5547 Subproject commit 106919aad41062055828df832acb863080e4b5bd

View file

@ -60,6 +60,7 @@ args=( "-jar" "$BABASHKA_JAR"
"--no-server" "--no-server"
"--report-unsupported-elements-at-runtime" "--report-unsupported-elements-at-runtime"
"--initialize-at-run-time=org.postgresql.sspi.SSPIClient" "--initialize-at-run-time=org.postgresql.sspi.SSPIClient"
"--initialize-at-run-time=org.httpkit.client.ClientSslEngineFactory\$SSLHolder"
"--native-image-info" "--native-image-info"
"--verbose" "--verbose"
"-H:ServiceLoaderFeatureExcludeServices=javax.sound.sampled.spi.AudioFileReader" "-H:ServiceLoaderFeatureExcludeServices=javax.sound.sampled.spi.AudioFileReader"

View file

@ -34,6 +34,7 @@ call %GRAALVM_HOME%\bin\native-image.cmd ^
"-H:ReflectionConfigurationFiles=reflection.json" ^ "-H:ReflectionConfigurationFiles=reflection.json" ^
"--initialize-at-build-time" ^ "--initialize-at-build-time" ^
"--initialize-at-run-time=org.postgresql.sspi.SSPIClient" ^ "--initialize-at-run-time=org.postgresql.sspi.SSPIClient" ^
"--initialize-at-run-time=org.httpkit.client.ClientSslEngineFactory\$SSLHolder" ^
"-H:EnableURLProtocols=http,https,jar" ^ "-H:EnableURLProtocols=http,https,jar" ^
"--enable-all-security-services" ^ "--enable-all-security-services" ^
"-H:+JNI" ^ "-H:+JNI" ^

View file

@ -14,7 +14,7 @@ unset BABASHKA_CLASSPATH
unset BABASHKA_PRELOADS_TEST unset BABASHKA_PRELOADS_TEST
echo "running tests part 1" echo "running tests part 1"
lein test "$@" lein "do" clean, test "$@"
export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")' export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
export BABASHKA_PRELOADS_TEST=true export BABASHKA_PRELOADS_TEST=true

View file

@ -100,6 +100,8 @@
java.io.OutputStream java.io.OutputStream
java.io.FileReader java.io.FileReader
java.io.InputStreamReader java.io.InputStreamReader
java.io.OutputStreamWriter
java.io.PrintStream
java.io.PushbackInputStream java.io.PushbackInputStream
java.io.Reader java.io.Reader
java.io.SequenceInputStream java.io.SequenceInputStream
@ -118,6 +120,7 @@
java.lang.Exception java.lang.Exception
java.lang.Float java.lang.Float
java.lang.IllegalArgumentException java.lang.IllegalArgumentException
java.lang.IndexOutOfBoundsException
java.lang.Integer java.lang.Integer
java.lang.Iterable java.lang.Iterable
java.lang.Long java.lang.Long
@ -216,7 +219,7 @@
java.util.jar.JarFile$JarFileEntry java.util.jar.JarFile$JarFileEntry
java.util.stream.Stream java.util.stream.Stream
java.util.Random java.util.Random
;; java.util.regex.Matcher java.util.regex.Matcher
java.util.regex.Pattern java.util.regex.Pattern
java.util.Base64 java.util.Base64
java.util.Base64$Decoder java.util.Base64$Decoder
@ -249,35 +252,58 @@
:methods [borkdude.graal.LockFix] ;; support for locking :methods [borkdude.graal.LockFix] ;; support for locking
:fields [clojure.lang.PersistentQueue] :fields [clojure.lang.PersistentQueue]
:instance-checks [clojure.lang.Cons :instance-checks [clojure.lang.APersistentMap ;; for proxy
clojure.lang.AMapEntry ;; for proxy
clojure.lang.Associative
clojure.lang.Atom
clojure.lang.Cons
clojure.lang.Counted
clojure.lang.Cycle clojure.lang.Cycle
clojure.lang.IObj clojure.lang.IObj
clojure.lang.Fn ;; to distinguish fns from maps, etc. clojure.lang.Fn ;; to distinguish fns from maps, etc.
clojure.lang.IFn clojure.lang.IFn
clojure.lang.IPending clojure.lang.IPending
;; clojure.lang.IDeref ;; clojure.lang.IDeref ;; implemented as protocol in sci
;; clojure.lang.IAtom ;; clojure.lang.IAtom ;; implemented as protocol in sci
clojure.lang.IEditableCollection clojure.lang.IEditableCollection
clojure.lang.IMapEntry clojure.lang.IMapEntry
clojure.lang.IMeta
clojure.lang.ILookup clojure.lang.ILookup
clojure.lang.IPersistentCollection clojure.lang.IPersistentCollection
clojure.lang.IPersistentMap clojure.lang.IPersistentMap
clojure.lang.IPersistentSet clojure.lang.IPersistentSet
;;clojure.lang.PersistentHashSet ;; temp for meander clojure.lang.IPersistentStack
clojure.lang.IPersistentVector clojure.lang.IPersistentVector
clojure.lang.IRecord clojure.lang.IRecord
clojure.lang.IReduce
clojure.lang.IReduceInit
clojure.lang.IKVReduce
clojure.lang.IRef clojure.lang.IRef
clojure.lang.ISeq clojure.lang.ISeq
clojure.lang.Indexed
clojure.lang.Iterate clojure.lang.Iterate
clojure.lang.LazySeq clojure.lang.LazySeq
clojure.lang.Named clojure.lang.Named
clojure.lang.Keyword clojure.lang.Keyword
clojure.lang.PersistentArrayMap
clojure.lang.PersistentHashMap
clojure.lang.PersistentHashSet
clojure.lang.PersistentList
clojure.lang.PersistentQueue
clojure.lang.PersistentStructMap
clojure.lang.PersistentTreeMap
clojure.lang.PersistentTreeSet
clojure.lang.PersistentVector
clojure.lang.Ratio clojure.lang.Ratio
clojure.lang.Repeat clojure.lang.Repeat
clojure.lang.Reversible
clojure.lang.Symbol clojure.lang.Symbol
clojure.lang.Sequential clojure.lang.Sequential
clojure.lang.Seqable clojure.lang.Seqable
java.util.List] clojure.lang.Volatile
java.util.List
java.util.Iterator
java.util.Map$Entry]
:custom ~custom-map}) :custom ~custom-map})
(defmacro gen-class-map [] (defmacro gen-class-map []

View file

@ -28,17 +28,18 @@
resource-paths))) resource-paths)))
(defn path-from-jar (defn path-from-jar
[^java.io.File jar-file resource-paths {:keys [:url?]}] [^java.io.File jar-file resource-paths opts]
(with-open [jar (JarFile. jar-file)] (let [url? (:url? opts)]
(some (fn [path] (with-open [jar (JarFile. jar-file)]
(when-let [entry (.getEntry jar path)] (some (fn [path]
(if url? (when-let [entry (.getEntry jar path)]
;; manual conversion, faster than going through .toURI (if url?
(java.net.URL. "jar" nil ;; manual conversion, faster than going through .toURI
(str "file:" (.getAbsolutePath jar-file) "!/" path)) (java.net.URL. "jar" nil
{:file path (str "file:" (.getAbsolutePath jar-file) "!/" path))
:source (slurp (.getInputStream jar entry))}))) {:file path
resource-paths))) :source (slurp (.getInputStream jar entry))})))
resource-paths))))
(deftype JarFileResolver [jar-file] (deftype JarFileResolver [jar-file]
IResourceResolver IResourceResolver
@ -57,8 +58,10 @@
(getResources [_ resource-paths opts] (getResources [_ resource-paths opts]
(keep #(getResource % resource-paths opts) entries))) (keep #(getResource % resource-paths opts) entries)))
(def path-sep (System/getProperty "path.separator"))
(defn loader [^String classpath] (defn loader [^String classpath]
(let [parts (.split classpath (System/getProperty "path.separator")) (let [parts (.split classpath path-sep)
entries (map part->entry parts)] entries (map part->entry parts)]
(Loader. entries))) (Loader. entries)))
@ -88,7 +91,7 @@
(fn [{:keys [:cp]}] (fn [{:keys [:cp]}]
(let [new-cp (let [new-cp
(if-not cp extra-classpath (if-not cp extra-classpath
(str cp (System/getProperty "path.separator") extra-classpath))] (str cp path-sep extra-classpath))]
{:loader (loader new-cp) {:loader (loader new-cp)
:cp new-cp}))) :cp new-cp})))
nil) nil)
@ -96,7 +99,7 @@
(defn split-classpath (defn split-classpath
"Returns the classpath as a seq of strings, split by the platform "Returns the classpath as a seq of strings, split by the platform
specific path separator." specific path separator."
([^String cp] (vec (.split cp (System/getProperty "path.separator"))))) ([^String cp] (vec (.split cp path-sep))))
(defn get-classpath (defn get-classpath
"Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath." "Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath."

View file

@ -20,6 +20,8 @@
ret#)) ret#))
(def data-readers (sci/new-dynamic-var '*data-readers* nil)) (def data-readers (sci/new-dynamic-var '*data-readers* nil))
(def command-line-args (sci/new-dynamic-var '*command-line-args* nil))
(def warn-on-reflection (sci/new-dynamic-var '*warn-on-reflection* false))
(defn read+string (defn read+string
"Added for compatibility. Must be used with "Added for compatibility. Must be used with
@ -59,4 +61,6 @@
'default-data-readers default-data-readers 'default-data-readers default-data-readers
'xml-seq (copy-core-var xml-seq) 'xml-seq (copy-core-var xml-seq)
'read+string (fn [& args] 'read+string (fn [& args]
(apply read+string @common/ctx args))}) (apply read+string @common/ctx args))
'*command-line-args* command-line-args
'*warn-on-reflection* warn-on-reflection})

View file

@ -57,11 +57,20 @@
then used to resolve dependencies in babashka." then used to resolve dependencies in babashka."
([deps-map] (add-deps deps-map nil)) ([deps-map] (add-deps deps-map nil))
([deps-map {:keys [:aliases]}] ([deps-map {:keys [:aliases]}]
(let [args ["-Spath" "-Sdeps" (str deps-map)] (when-let [paths (:paths deps-map)]
args (cond-> args (cp/add-classpath (str/join cp/path-sep paths)))
aliases (conj (str "-A:" (str/join ":" aliases)))) (when-let [deps-map (not-empty (dissoc deps-map :paths :tasks))]
cp (with-out-str (apply deps/-main args))] (let [deps-map (assoc-in deps-map [:aliases :org.babashka/defaults]
(cp/add-classpath cp)))) '{:replace-paths [] ;; babashka sets paths manually
:classpath-overrides {org.clojure/clojure ""
org.clojure/spec.alpha ""
org.clojure/core.specs.alpha ""}})
args ["-Spath" "-Sdeps" (str deps-map)]
args (conj args (str "-A:" (str/join ":" (cons ":org.babashka/defaults" aliases))))
cp (with-out-str (apply deps/-main args))
cp (str/trim cp)
cp (str/replace cp (re-pattern (str cp/path-sep "+$")) "")]
(cp/add-classpath cp)))))
(defn clojure (defn clojure
"Starts clojure similar to CLI. Use `rlwrap bb` for `clj`-like invocation. "Starts clojure similar to CLI. Use `rlwrap bb` for `clj`-like invocation.

View file

@ -25,6 +25,7 @@
'create-dir (sci/copy-var fs/create-dir fns) 'create-dir (sci/copy-var fs/create-dir fns)
'create-dirs (sci/copy-var fs/create-dirs fns) 'create-dirs (sci/copy-var fs/create-dirs fns)
'create-file (sci/copy-var fs/create-file fns) 'create-file (sci/copy-var fs/create-file fns)
'create-link (sci/copy-var fs/create-link fns)
'create-sym-link (sci/copy-var fs/create-sym-link fns) 'create-sym-link (sci/copy-var fs/create-sym-link fns)
'create-temp-dir (sci/copy-var fs/create-temp-dir fns) 'create-temp-dir (sci/copy-var fs/create-temp-dir fns)
'creation-time (sci/copy-var fs/creation-time fns) 'creation-time (sci/copy-var fs/creation-time fns)
@ -37,6 +38,7 @@
'exec-paths (sci/copy-var fs/exec-paths fns) 'exec-paths (sci/copy-var fs/exec-paths fns)
'executable? (sci/copy-var fs/executable? fns) 'executable? (sci/copy-var fs/executable? fns)
'exists? (sci/copy-var fs/exists? fns) 'exists? (sci/copy-var fs/exists? fns)
'extension (sci/copy-var fs/extension fns)
'file (sci/copy-var fs/file fns) 'file (sci/copy-var fs/file fns)
'file-name (sci/copy-var fs/file-name fns) 'file-name (sci/copy-var fs/file-name fns)
'file-separator (sci/copy-var fs/file-separator fns) 'file-separator (sci/copy-var fs/file-separator fns)
@ -62,6 +64,7 @@
'read-attributes (sci/copy-var fs/read-attributes fns) 'read-attributes (sci/copy-var fs/read-attributes fns)
'readable? (sci/copy-var fs/readable? fns) 'readable? (sci/copy-var fs/readable? fns)
'real-path (sci/copy-var fs/real-path fns) 'real-path (sci/copy-var fs/real-path fns)
'regular-file? (sci/copy-var fs/regular-file? fns)
'relative? (sci/copy-var fs/relative? fns) 'relative? (sci/copy-var fs/relative? fns)
'relativize (sci/copy-var fs/relativize fns) 'relativize (sci/copy-var fs/relativize fns)
'same-file? (sci/copy-var fs/same-file? fns) 'same-file? (sci/copy-var fs/same-file? fns)
@ -70,6 +73,7 @@
'set-last-modified-time (sci/copy-var fs/set-last-modified-time fns) 'set-last-modified-time (sci/copy-var fs/set-last-modified-time fns)
'set-posix-file-permissions (sci/copy-var fs/set-posix-file-permissions fns) 'set-posix-file-permissions (sci/copy-var fs/set-posix-file-permissions fns)
'size (sci/copy-var fs/size fns) 'size (sci/copy-var fs/size fns)
'split-ext (sci/copy-var fs/split-ext fns)
'split-paths (sci/copy-var fs/split-paths fns) 'split-paths (sci/copy-var fs/split-paths fns)
'starts-with? (sci/copy-var fs/starts-with? fns) 'starts-with? (sci/copy-var fs/starts-with? fns)
'str->posix (sci/copy-var fs/str->posix fns) 'str->posix (sci/copy-var fs/str->posix fns)

View file

@ -22,6 +22,8 @@
'start (copy-var process/start tns) 'start (copy-var process/start tns)
'pipeline (copy-var process/pipeline tns) 'pipeline (copy-var process/pipeline tns)
'$ (copy-var process/$ tns) '$ (copy-var process/$ tns)
'sh (copy-var process/sh tns)
'tokenize (copy-var process/tokenize tns)
'*defaults* defaults '*defaults* defaults
'destroy (copy-var process/destroy tns) 'destroy (copy-var process/destroy tns)
'destroy-tree (copy-var process/destroy-tree tns)}) 'destroy-tree (copy-var process/destroy-tree tns)})

View file

@ -0,0 +1,60 @@
(ns babashka.impl.proxy
{:no-doc true}
(:require [sci.impl.types]))
(set! *warn-on-reflection* false)
(defn method-or-bust [methods k]
(or (get methods k)
(throw (UnsupportedOperationException. (str "Method not implemented: " k)))))
(defn class-name [^Class clazz]
(.getName clazz))
(defn proxy-fn [{:keys [class interfaces protocols methods]}]
(let [interface-names (set (map class-name interfaces))]
(case [(class-name class) interface-names]
;; This combination is used by pathom3
["clojure.lang.APersistentMap" #{"clojure.lang.IMeta" "clojure.lang.IObj"}]
(proxy [clojure.lang.APersistentMap clojure.lang.IMeta clojure.lang.IObj sci.impl.types.IReified] []
(getInterfaces []
interfaces)
(getMethods []
methods)
(getProtocols []
protocols)
(iterator [] ((method-or-bust methods 'iterator) this))
(containsKey [k] ((method-or-bust methods 'containsKey) this k))
(entryAt [k] ((method-or-bust methods 'entryAt) this k))
(valAt
([k]
((method-or-bust methods 'valAt) this k))
([k default] ((method-or-bust methods 'valAt) this k default)))
(cons [v]
(if-let [m (get methods 'cons)]
(m this v)
(proxy-super cons v)))
(count [] ((method-or-bust methods 'count) this))
(assoc [k v] ((method-or-bust methods 'assoc) this k v))
(without [k] ((method-or-bust methods 'without) this k))
(seq [] ((method-or-bust methods 'seq) this))
(equiv [other]
(if-let [m (get methods 'equiv)]
(m this other)
(proxy-super equiv other)))
(empty [] ((method-or-bust methods 'empty) this))
(meta [] ((method-or-bust methods 'meta) this))
(withMeta [meta] ((method-or-bust methods 'withMeta) this meta))
(toString []
(if-let [m (get methods 'toString)]
(m this)
(proxy-super toString))))
["clojure.lang.AMapEntry" #{}]
(proxy [clojure.lang.AMapEntry] []
(key [] ((method-or-bust methods 'key) this))
(val [] ((method-or-bust methods 'val) this))
(getKey [] ((method-or-bust methods 'getKey) this))
(getValue [] ((method-or-bust methods 'getValue) this))))))

View file

@ -1,40 +1,153 @@
(ns babashka.impl.reify (ns babashka.impl.reify
{:no-doc true} {:no-doc true}
(:require [clojure.math.combinatorics :as combo])) (:require [sci.impl.types]))
(set! *warn-on-reflection* false) (set! *warn-on-reflection* false)
;; Notes
;; We abandoned the 'one reify object that implements all interfaces' approach
;; due to false positives. E.g. when you would print a reified object, you would
;; get: 'Not implemented: seq', because print-method thought this object was
;; seqable, while in fact, it wasn't.
(defn method-or-bust [methods k]
(or (get methods k)
(throw (UnsupportedOperationException. "Method not implemented: " k))))
(defmacro gen-reify-combos (defmacro gen-reify-combos
"Generates pre-compiled reify combinations" "Generates pre-compiled reify combinations"
[methods] [methods]
(let [subsets (rest (combo/subsets (seq methods)))] (let [prelude '(reify
(reduce (fn [opts classes] sci.impl.types.IReified
(assoc opts (getInterfaces [this]
(set (map (fn [[class _]] interfaces)
(list 'quote class)) (getMethods [this]
classes)) methods)
(list 'fn ['methods] (getProtocols [this]
(list* 'reify protocols))]
(mapcat (list 'fn [{:keys '[interfaces methods protocols]}]
(fn [[clazz methods]] `(cond ~'(empty? interfaces) ~prelude ~'(> (count interfaces)
(cons clazz 1) (throw (new Exception "Babashka currently does not support reifying more than one interface."))
(map :else
(fn [[meth args]] (case (.getName ~(with-meta '(first interfaces)
(list meth args {:tag 'Class}))
(list* ~@(mapcat
(list 'get-in 'methods (fn [[clazz methods]]
[(list 'quote clazz) (list 'quote meth)]) (list
args))) (str clazz)
methods))) (concat prelude
classes))))) (cons clazz
{} (mapcat
subsets))) (fn [[meth arities]]
(map
(fn [arity]
(list meth arity
(list*
(list 'or (list 'get 'methods (list 'quote meth))
`(throw (new Exception (str "Not implemented: "
~(str meth)))))
arity)))
arities))
methods)))))
methods))))))
;; (require 'clojure.pprint)
;; (clojure.pprint/pprint
;; (macroexpand '(gen-reify-combos {java.nio.file.FileVisitor
;; {preVisitDirectory [[this p attrs]]
;; postVisitDirectory [[this p attrs]]
;; visitFile [[this p attrs]]}})))
#_:clj-kondo/ignore #_:clj-kondo/ignore
(def reify-opts (def reify-fn
(gen-reify-combos (gen-reify-combos
{java.nio.file.FileVisitor {preVisitDirectory [this p attrs] {java.lang.Object
postVisitDirectory [this p attrs] {toString [[this]]}
visitFile [this p attrs]} java.nio.file.FileVisitor
java.io.FileFilter {accept [this f]} {preVisitDirectory [[this p attrs]]
java.io.FilenameFilter {accept [this f s]}})) postVisitDirectory [[this p attrs]]
visitFile [[this p attrs]]}
java.io.FileFilter
{accept [[this f]]}
java.io.FilenameFilter
{accept [[this f s]]}
clojure.lang.Associative
{containsKey [[this k]]
entryAt [[this k]]
assoc [[this k v]]}
clojure.lang.ILookup
{valAt [[this k] [this k default]]}
java.util.Map$Entry
{getKey [[this]]
getValue [[this]]}
clojure.lang.IFn
{applyTo [[this arglist]]
invoke [[this]
[this a1]
[this a1 a2]
[this a1 a2 a3]
[this a1 a2 a3 a4]
[this a1 a2 a3 a4 a5]
[this a1 a2 a3 a4 a5 a6]
[this a1 a2 a3 a4 a5 a6 a7]
[this a1 a2 a3 a4 a5 a6 a7 a8]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20]
[this a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 varargs]]}
clojure.lang.IPersistentCollection
{count [[this]]
cons [[this x]]
empty [[this]]
equiv [[this x]]}
clojure.lang.IReduce
{reduce [[this f]]}
clojure.lang.IReduceInit
{reduce [[this f initial]]}
clojure.lang.IKVReduce
{kvreduce [[this f initial]]}
clojure.lang.Indexed
{nth [[this n] [this n not-found]]}
clojure.lang.IPersistentMap
{assocEx [[this k v]]
without [[this k]]}
clojure.lang.IPersistentStack
{peek [[this]]
pop [[this]]}
clojure.lang.Reversible
{rseq [[this]]}
clojure.lang.Seqable
{seq [[this]]}
java.lang.Iterable
{iterator [[this]]
forEach [[this action]]}
java.util.Iterator
{hasNext [[this]]
next [[this]]}}))

View file

@ -2,6 +2,7 @@
{:no-doc true} {:no-doc true}
(:refer-clojure :exclude [error-handler]) (:refer-clojure :exclude [error-handler])
(:require (:require
[babashka.fs :as fs]
[babashka.impl.bencode :refer [bencode-namespace]] [babashka.impl.bencode :refer [bencode-namespace]]
[babashka.impl.cheshire :refer [cheshire-core-namespace]] [babashka.impl.cheshire :refer [cheshire-core-namespace]]
[babashka.impl.classes :as classes] [babashka.impl.classes :as classes]
@ -26,7 +27,8 @@
[babashka.impl.pprint :refer [pprint-namespace]] [babashka.impl.pprint :refer [pprint-namespace]]
[babashka.impl.process :refer [process-namespace]] [babashka.impl.process :refer [process-namespace]]
[babashka.impl.protocols :refer [protocols-namespace]] [babashka.impl.protocols :refer [protocols-namespace]]
[babashka.impl.reify :refer [reify-opts]] [babashka.impl.proxy :refer [proxy-fn]]
[babashka.impl.reify :refer [reify-fn]]
[babashka.impl.repl :as repl] [babashka.impl.repl :as repl]
[babashka.impl.socket-repl :as socket-repl] [babashka.impl.socket-repl :as socket-repl]
[babashka.impl.test :as t] [babashka.impl.test :as t]
@ -73,185 +75,101 @@
;; echo '1' | java -agentlib:native-image-agent=config-output-dir=/tmp -jar target/babashka-xxx-standalone.jar '...' ;; echo '1' | java -agentlib:native-image-agent=config-output-dir=/tmp -jar target/babashka-xxx-standalone.jar '...'
;; with the java provided by GraalVM. ;; with the java provided by GraalVM.
(defn parse-opts [options]
(let [opts (loop [options options
opts-map {}]
(if options
(let [opt (first options)]
(case opt
("--") (assoc opts-map :command-line-args (next options))
("--clojure") (assoc opts-map :clojure true
:opts (rest options))
("--version") {:version true}
("--help" "-h" "-?") {:help? true}
("--verbose")(recur (next options)
(assoc opts-map
:verbose? true))
("--describe") (recur (next options)
(assoc opts-map
:describe? true))
("--stream") (recur (next options)
(assoc opts-map
:stream? true))
("-i") (recur (next options)
(assoc opts-map
:shell-in true))
("-I") (recur (next options)
(assoc opts-map
:edn-in true))
("-o") (recur (next options)
(assoc opts-map
:shell-out true))
("-O") (recur (next options)
(assoc opts-map
:edn-out true))
("-io") (recur (next options)
(assoc opts-map
:shell-in true
:shell-out true))
("-iO") (recur (next options)
(assoc opts-map
:shell-in true
:edn-out true))
("-Io") (recur (next options)
(assoc opts-map
:edn-in true
:shell-out true))
("-IO") (recur (next options)
(assoc opts-map
:edn-in true
:edn-out true))
("--classpath", "-cp")
(let [options (next options)]
(recur (next options)
(assoc opts-map :classpath (first options))))
("--uberscript")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:uberscript (first options))))
("--uberjar")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:uberjar (first options))))
("-f" "--file")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:file (first options))))
("--jar" "-jar")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:jar (first options))))
("--repl")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:repl true)))
("--socket-repl")
(let [options (next options)
opt (first options)
opt (when (and opt (not (str/starts-with? opt "-")))
opt)
options (if opt (next options)
options)]
(recur options
(assoc opts-map
:socket-repl (or opt "1666"))))
("--nrepl-server")
(let [options (next options)
opt (first options)
opt (when (and opt (not (str/starts-with? opt "-")))
opt)
options (if opt (next options)
options)]
(recur options
(assoc opts-map
:nrepl (or opt "1667"))))
("--eval", "-e")
(let [options (next options)]
(recur (next options)
(update opts-map :expressions (fnil conj []) (first options))))
("--main", "-m")
(let [options (next options)]
(recur (next options)
(assoc opts-map :main (first options))))
(if (some opts-map [:file :jar :socket-repl :expressions :main])
(assoc opts-map
:command-line-args options)
(let [trimmed-opt (str/triml opt)
c (.charAt trimmed-opt 0)]
(case c
(\( \{ \[ \* \@ \#)
(-> opts-map
(update :expressions (fnil conj []) (first options))
(assoc :command-line-args (next options)))
(assoc opts-map
(if (str/ends-with? opt ".jar")
:jar :file) opt
:command-line-args (next options)))))))
opts-map))]
opts))
(def version (str/trim (slurp (io/resource "BABASHKA_VERSION")))) (def version (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
(defn print-version [] (defn print-version []
(println (str "babashka v" version))) (println (str "babashka v" version)))
(def bb-edn
(volatile! nil))
(defn print-help [] (defn command? [x]
(case x
("clojure"
"version"
"help"
"doc"
"tasks"
"uberjar"
"uberscript"
"repl"
"socket-repl"
"nrepl-server"
"describe") true
false))
(defn print-error [& msgs]
(binding [*out* *err*]
(apply println msgs)))
(defn print-help [_ctx _command-line-args]
(println (str "Babashka v" version)) (println (str "Babashka v" version))
;; (println (str "sci v" (str/trim (slurp (io/resource "SCI_VERSION")))))
(println)
(println "Options must appear in the order of groups mentioned below.")
(println " (println "
Help: Usage: bb [classpath opts] [eval opts] [cmdline args]
or: bb [classpath opts] file [cmdline args]
or: bb [classpath opts] subcommand [subcommand opts] [cmdline args]
--help, -h or -? Print this help text. Classpath:
--version Print the current version of babashka.
--describe Print an EDN map with information about this version of babashka. -cp, --classpath Classpath to use. Overrides bb.edn classpath.
Evaluation: Evaluation:
-e, --eval <expr> Evaluate an expression. -e, --eval <expr> Evaluate an expression.
-f, --file <path> Evaluate a file. -f, --file <path> Evaluate a file.
-cp, --classpath Classpath to use. -m, --main <ns|var> Call the -main function from a namespace or call a fully qualified var.
-m, --main <ns> Call the -main function from namespace with args. --verbose Print debug information and entire stacktrace in case of exception.
--verbose Print debug information and entire stacktrace in case of exception.
Help:
help, -h or -? Print this help text.
version Print the current version of babashka.
describe Print an EDN map with information about this version of babashka.
doc <var|ns> Print docstring of var or namespace. Requires namespace if necessary.
REPL: REPL:
--repl Start REPL. Use rlwrap for history. 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). socket-repl [addr] Start a socket REPL. Addr opt defaults to localhost: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). nrepl-server [addr] Start nREPL server. Address option defaults to locahost:1667.
In- and output flags:
-i Bind *input* to a lazy seq of lines from stdin.
-I Bind *input* to a lazy seq of EDN values from stdin.
-o Write lines to stdout.
-O Write EDN values to stdout.
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration.
Uberscript:
--uberscript <file> Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single file.
Uberjar:
--uberjar <jar> Similar to --uberscript but creates jar file.
Clojure: Clojure:
--clojure [args...] Invokes clojure. Takes same args as the official clojure CLI. clojure [args...] Invokes clojure. Takes same args as the official clojure CLI.
If the first argument is not any of the above options, then it treated as a file if it exists, or as an expression otherwise. Packaging:
Everything after that is bound to *command-line-args*.
uberscript <file> [eval-opt] Collect all required namespaces from the classpath into a single file. Accepts additional eval opts, like `-m`.
uberjar <jar> [eval-opt] Similar to uberscript but creates jar file.
In- and output flags (only to be used with -e one-liners):
-i Bind *input* to a lazy seq of lines from stdin.
-I Bind *input* to a lazy seq of EDN values from stdin.
-o Write lines to stdout.
-O Write EDN values to stdout.
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration.
File names take precedence over subcommand names.
Remaining arguments are bound to *command-line-args*.
Use -- to separate script command line args from bb command line args. Use -- to separate script command line args from bb command line args.
")) When no eval opts or subcommand is provided, the implicit subcommand is repl.")
[nil 0])
(defn print-doc [ctx command-line-args]
(let [arg (first command-line-args)]
(if (sci/eval-string* ctx (format "
(when (or (resolve '%1$s)
(if (simple-symbol? '%1$s)
(try (require '%1$s) true
(catch Exception e nil))
(try (requiring-resolve '%1$s) true
(catch Exception e nil))))
(clojure.repl/doc %1$s)
true)" arg))
[nil 0]
[nil 1]))
,)
(defn print-describe [] (defn print-describe []
(println (println
@ -302,8 +220,6 @@ Use -- to separate script command line args from bb command line args.
(str/replace x #"^#!.*" "")) (str/replace x #"^#!.*" ""))
(throw (Exception. (str "File does not exist: " file)))))) (throw (Exception. (str "File does not exist: " file))))))
(def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false))
(defn load-file* [f] (defn load-file* [f]
(let [f (io/file f) (let [f (io/file f)
s (slurp f)] s (slurp f)]
@ -320,7 +236,7 @@ Use -- to separate script command line args from bb command line args.
nrepl-opts (assoc nrepl-opts nrepl-opts (assoc nrepl-opts
:debug dev? :debug dev?
:describe {"versions" {"babashka" version}} :describe {"versions" {"babashka" version}}
:thread-bind [reflection-var])] :thread-bind [core/warn-on-reflection])]
(nrepl-server/start-server! ctx nrepl-opts) (nrepl-server/start-server! ctx nrepl-opts)
(binding [*out* *err*] (binding [*out* *err*]
(println "For more info visit: https://book.babashka.org/#_nrepl"))) (println "For more info visit: https://book.babashka.org/#_nrepl")))
@ -444,6 +360,7 @@ Use -- to separate script command line args from bb command line args.
Comparable java.lang.Comparable Comparable java.lang.Comparable
Double java.lang.Double Double java.lang.Double
Exception java.lang.Exception Exception java.lang.Exception
IndexOutOfBoundsException java.lang.IndexOutOfBoundsException
IllegalArgumentException java.lang.IllegalArgumentException IllegalArgumentException java.lang.IllegalArgumentException
Integer java.lang.Integer Integer java.lang.Integer
Iterable java.lang.Iterable Iterable java.lang.Iterable
@ -483,27 +400,156 @@ Use -- to separate script command line args from bb command line args.
(defn shell-seq [in] (defn shell-seq [in]
(line-seq (java.io.BufferedReader. in))) (line-seq (java.io.BufferedReader. in)))
(defn main (defn parse-opts [options]
[& args] (let [opt (first options)]
(handle-pipe!) (cond (and (command? opt)
(handle-sigint!) (not (fs/regular-file? opt)))
(recur (cons (str "--" opt) (next options)))
:else
(let [opts (loop [options options
opts-map {}]
(if options
(let [opt (first options)]
(case opt
("--") (assoc opts-map :command-line-args (next options))
("--clojure") (assoc opts-map :clojure true
:command-line-args (rest options))
("--version") {:version true}
("--help" "-h" "-?" "help")
{:help true
:command-line-args (rest options)}
("--doc")
{:doc true
:command-line-args (rest options)}
("--verbose") (recur (next options)
(assoc opts-map
:verbose? true))
("--describe") (recur (next options)
(assoc opts-map
:describe? true))
("--stream") (recur (next options)
(assoc opts-map
:stream? true))
("-i") (recur (next options)
(assoc opts-map
:shell-in true))
("-I") (recur (next options)
(assoc opts-map
:edn-in true))
("-o") (recur (next options)
(assoc opts-map
:shell-out true))
("-O") (recur (next options)
(assoc opts-map
:edn-out true))
("-io") (recur (next options)
(assoc opts-map
:shell-in true
:shell-out true))
("-iO") (recur (next options)
(assoc opts-map
:shell-in true
:edn-out true))
("-Io") (recur (next options)
(assoc opts-map
:edn-in true
:shell-out true))
("-IO") (recur (next options)
(assoc opts-map
:edn-in true
:edn-out true))
("--classpath", "-cp")
(let [options (next options)]
(recur (next options)
(assoc opts-map :classpath (first options))))
("--uberscript")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:uberscript (first options))))
("--uberjar")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:uberjar (first options))))
("-f" "--file")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:file (first options))))
("--jar" "-jar")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:jar (first options))))
("--repl")
(let [options (next options)]
(recur (next options)
(assoc opts-map
:repl true)))
("--socket-repl")
(let [options (next options)
opt (first options)
opt (when (and opt (not (str/starts-with? opt "-")))
opt)
options (if opt (next options)
options)]
(recur options
(assoc opts-map
:socket-repl (or opt "1666"))))
("--nrepl-server")
(let [options (next options)
opt (first options)
opt (when (and opt (not (str/starts-with? opt "-")))
opt)
options (if opt (next options)
options)]
(recur options
(assoc opts-map
:nrepl (or opt "1667"))))
("--eval", "-e")
(let [options (next options)]
(recur (next options)
(update opts-map :expressions (fnil conj []) (first options))))
("--main", "-m",)
(let [options (next options)]
(recur (next options)
(assoc opts-map :main (first options))))
;; fallback
(if (some opts-map [:file :jar :socket-repl :expressions :main])
(assoc opts-map
:command-line-args options)
(let [trimmed-opt (str/triml opt)
c (.charAt trimmed-opt 0)]
(case c
(\( \{ \[ \* \@ \#)
(-> opts-map
(update :expressions (fnil conj []) (first options))
(assoc :command-line-args (next options)))
(assoc opts-map
(if (str/ends-with? opt ".jar")
:jar :file) opt
:command-line-args (next options)))))))
opts-map))]
opts))))
(def env (atom {}))
(defn exec [opts]
(binding [*unrestricted* true] (binding [*unrestricted* true]
(sci/binding [reflection-var false (sci/binding [core/warn-on-reflection @core/warn-on-reflection
core/data-readers @core/data-readers core/data-readers @core/data-readers
sci/ns @sci/ns] sci/ns @sci/ns]
(let [{version-opt :version (let [{version-opt :version
:keys [:shell-in :edn-in :shell-out :edn-out :keys [:shell-in :edn-in :shell-out :edn-out
:help? :file :command-line-args :help :file :command-line-args
:expressions :stream? :expressions :stream?
:repl :socket-repl :nrepl :repl :socket-repl :nrepl
:verbose? :classpath :verbose? :classpath
:main :uberscript :describe? :main :uberscript :describe?
:jar :uberjar :clojure] :as opts} :jar :uberjar :clojure
(parse-opts args) :doc]}
_ (when clojure opts
(if-let [proc (deps/clojure (:opts opts))]
(-> @proc :exit (System/exit))
(System/exit 0)))
_ (when verbose? (vreset! common/verbose? true)) _ (when verbose? (vreset! common/verbose? true))
_ (do ;; set properties _ (do ;; set properties
(when main (System/setProperty "babashka.main" main)) (when main (System/setProperty "babashka.main" main))
@ -522,11 +568,18 @@ Use -- to separate script command line args from bb command line args.
:else :else
(edn/read {:readers edn-readers} *in*)))))) (edn/read {:readers edn-readers} *in*))))))
uberscript-sources (atom ()) uberscript-sources (atom ())
env (atom {})
classpath (or classpath classpath (or classpath
(System/getenv "BABASHKA_CLASSPATH")) (System/getenv "BABASHKA_CLASSPATH"))
_ (when classpath _ (if classpath
(cp/add-classpath classpath)) (cp/add-classpath classpath)
;; when classpath isn't set, we calculate it from bb.edn, if present
(let [bb-edn-file (or (System/getenv "BABASHKA_EDN")
"bb.edn")]
(when (fs/exists? bb-edn-file)
(let [edn (edn/read-string (slurp bb-edn-file))]
(vreset! bb-edn edn)))
;; we mutate the atom from tests as well, so despite the above it can contain a bb.edn
(when-let [bb-edn @bb-edn] (deps/add-deps bb-edn))))
abs-path (when file abs-path (when file
(let [abs-path (.getAbsolutePath (io/file file))] (let [abs-path (.getAbsolutePath (io/file file))]
(vars/bindRoot sci/file abs-path) (vars/bindRoot sci/file abs-path)
@ -552,15 +605,11 @@ Use -- to separate script command line args from bb command line args.
["META-INF/MANIFEST.MF"] {:url? true})] ["META-INF/MANIFEST.MF"] {:url? true})]
(cp/main-ns res)) (cp/main-ns res))
main) main)
;; TODO: pull more of these values to compile time ;; TODO: pull more of these values to compile time
opts {:aliases aliases opts {:aliases aliases
:namespaces (-> namespaces :namespaces (-> namespaces
(assoc 'clojure.core (assoc 'clojure.core
(assoc core-extras (assoc core-extras
'*command-line-args*
(sci/new-dynamic-var '*command-line-args* command-line-args)
'*warn-on-reflection* reflection-var
'load-file load-file*)) 'load-file load-file*))
(assoc-in ['clojure.java.io 'resource] (assoc-in ['clojure.java.io 'resource]
(fn [path] (fn [path]
@ -577,15 +626,23 @@ Use -- to separate script command line args from bb command line args.
:load-fn load-fn :load-fn load-fn
:uberscript uberscript :uberscript uberscript
:readers core/data-readers :readers core/data-readers
:reify reify-opts} :reify-fn reify-fn
:proxy-fn proxy-fn}
opts (addons/future opts) opts (addons/future opts)
sci-ctx (sci/init opts) sci-ctx (sci/init opts)
_ (vreset! common/ctx sci-ctx) _ (vreset! common/ctx sci-ctx)
preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim)) preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim))
[expressions exit-code] [expressions exit-code]
(cond expressions [expressions nil] (cond expressions [expressions nil]
main [[(format "(ns user (:require [%1$s])) (apply %1$s/-main *command-line-args*)" main
main)] nil] (let [sym (symbol main)
ns? (namespace sym)
ns (or ns? sym)
var-name (if ns?
(name sym)
"-main")]
[[(format "(ns user (:require [%1$s])) (apply %1$s/%2$s *command-line-args*)"
ns var-name)] nil])
file (try [[(read-file file)] nil] file (try [[(read-file file)] nil]
(catch Exception e (catch Exception e
(error-handler e {:expression expressions (error-handler e {:expression expressions
@ -615,8 +672,8 @@ Use -- to separate script command line args from bb command line args.
(second (second
(cond version-opt (cond version-opt
[(print-version) 0] [(print-version) 0]
help? help (print-help sci-ctx command-line-args)
[(print-help) 0] doc (print-doc sci-ctx command-line-args)
describe? describe?
[(print-describe) 0] [(print-describe) 0]
repl [(repl/start-repl! sci-ctx) 0] repl [(repl/start-repl! sci-ctx) 0]
@ -631,7 +688,8 @@ Use -- to separate script command line args from bb command line args.
[nil 0] ;; done streaming [nil 0] ;; done streaming
(let [res [(let [res (let [res [(let [res
(sci/binding [sci/file (or @sci/file "<expr>") (sci/binding [sci/file (or @sci/file "<expr>")
input-var in] input-var in
core/command-line-args command-line-args]
(sci/eval-string* sci-ctx expression))] (sci/eval-string* sci-ctx expression))]
(when (some? res) (when (some? res)
(if-let [pr-f (cond shell-out println (if-let [pr-f (cond shell-out println
@ -650,6 +708,9 @@ Use -- to separate script command line args from bb command line args.
:verbose? verbose? :verbose? verbose?
:preloads preloads :preloads preloads
:loader (:loader @cp/cp-state)})))) :loader (:loader @cp/cp-state)}))))
clojure [nil (if-let [proc (deps/clojure command-line-args)]
(-> @proc :exit)
0)]
uberscript [nil 0] uberscript [nil 0]
:else [(repl/start-repl! sci-ctx) 0])) :else [(repl/start-repl! sci-ctx) 0]))
1)] 1)]
@ -669,8 +730,14 @@ Use -- to separate script command line args from bb command line args.
:verbose verbose?})) :verbose verbose?}))
exit-code)))) exit-code))))
(defn main [& args]
(let [opts (parse-opts args)]
(exec opts)))
(defn -main (defn -main
[& args] [& args]
(handle-pipe!)
(handle-sigint!)
(if-let [dev-opts (System/getenv "BABASHKA_DEV")] (if-let [dev-opts (System/getenv "BABASHKA_DEV")]
(let [{:keys [:n]} (if (= "true" dev-opts) {:n 1} (let [{:keys [:n]} (if (= "true" dev-opts) {:n 1}
(edn/read-string dev-opts)) (edn/read-string dev-opts))

View file

@ -0,0 +1,10 @@
(ns user
(:require [babashka.process :as p]
[clojure.string :as str]))
(defn bash [& args]
;; (prn :cmd *command-line-args*)
(-> (p/process ["bash" "-c" (str/join " " args)]
{:inherit true})
p/check)
nil)

View file

@ -6,10 +6,12 @@
(def status (atom {})) (def status (atom {}))
(defn test-namespace? [ns]
(or (empty? ns-args)
(contains? ns-args ns)))
(defn test-namespaces [& namespaces] (defn test-namespaces [& namespaces]
(let [namespaces (if (seq ns-args) (let [namespaces (seq (filter test-namespace? namespaces))]
(seq (keep ns-args namespaces))
namespaces)]
(when namespaces (when namespaces
(doseq [ns namespaces] (doseq [ns namespaces]
(require ns)) (require ns))
@ -121,7 +123,14 @@
;;;; doric ;;;; doric
(test-namespaces 'doric.test.core) (defn test-doric-cyclic-dep-problem
[]
(require '[doric.core :as d])
((resolve 'doric.core/table) [:a :b] [{:a 1 :b 2}]))
(when (test-namespace? 'doric.test.core)
(test-doric-cyclic-dep-problem)
(test-namespaces 'doric.test.core))
;;;; cljc-java-time ;;;; cljc-java-time

View file

@ -1,9 +1,10 @@
(ns version-clj.compare-test (ns version-clj.compare-test
(:require [clojure.test :refer [deftest are]] (:require #?(:clj [clojure.test :refer [deftest are]]
:cljs [cljs.test :refer-macros [deftest are]])
[version-clj.compare :refer [version-compare]])) [version-clj.compare :refer [version-compare]]))
(deftest t-version-compare (deftest t-version-compare
(are [v0 v1 r] (= (version-compare v0 v1) r) (are [v0 v1 r] (= r (version-compare v0 v1))
;; Numeric Comparison ;; Numeric Comparison
"1.0.0" "1.0.0" 0 "1.0.0" "1.0.0" 0
"1.0.0" "1.0" 0 "1.0.0" "1.0" 0
@ -36,6 +37,19 @@
"1.0-RC5" "1.0-RC20" -1 "1.0-RC5" "1.0-RC20" -1
"1.0-RC11" "1.0-RC6" 1 "1.0-RC11" "1.0-RC6" 1
;; Comparison nested vs. value
"1.0.0" "1.0-1.0" -1
"1.0-1.0" "1.0.0" 1
"1.0-0.0" "1.0.0" 0
"1.0.0" "1.0-0.0" 0
"1.x.0" "1.x-1.0" -1
"1.x-1.0" "1.x.0" 1
"1.0-612" "1.0.613" -1
;; Numbers are newer than strings
"1.x.1" "1.0.1" -1
"1.0.1" "1.x.1" 1
;; Releases are newer than SNAPSHOTs ;; Releases are newer than SNAPSHOTs
"1.0.0" "1.0.0-SNAPSHOT" 1 "1.0.0" "1.0.0-SNAPSHOT" 1
"1.0.0-SNAPSHOT" "1.0.0-SNAPSHOT" 0 "1.0.0-SNAPSHOT" "1.0.0-SNAPSHOT" 0

View file

@ -1,25 +1,81 @@
(ns version-clj.core-test (ns version-clj.core-test
(:require [clojure.test :refer [deftest are]] (:require #?(:clj [clojure.test :refer [deftest is are]]
[version-clj.core :refer [snapshot? qualified?]])) :cljs [cljs.test :refer-macros [deftest is are]])
[version-clj.core :as v]))
(deftest t-snapshot (deftest t-snapshot?
(are [v r] (= (boolean (snapshot? v)) r) (are [v r] (= r (boolean (v/snapshot? v)))
"1.0.0" false "1.0.0" false
"SNAPSHOT" true "SNAPSHOT" true
"1-SNAPSHOT" true "1-SNAPSHOT" true
"1.0-SNAPSHOT" true "1.0-SNAPSHOT" true
"1.0-SNAPSHOT.2" true "1.0-SNAPSHOT.2" true
"1.0-NOSNAPSHOT" false)) "1.0-NOSNAPSHOT" false))
(deftest t-qualified (deftest t-qualified?
(are [v r] (= (boolean (qualified? v)) r) (are [v r] (= r (boolean (v/qualified? v)))
"1.0.0" false "1.0.0" false
"SNAPSHOT" true "SNAPSHOT" true
"1-SNAPSHOT" true "SNAPSHOT2" true
"1.0-SNAPSHOT" true "1-SNAPSHOT" true
"1.0-SNAPSHOT.2" true "1.0-SNAPSHOT" true
"1.0-NOSNAPSHOT" true "1.0-SNAPSHOT.2" true
"1.x.2" false "1.0-NOSNAPSHOT" true
"1.2y" true "1.0-NOSNAPSHOT.1" true
"1.y2" false "1.0-NOSNAPSHOT.1.1" true
"1.y" false)) "1.0-NOSNAPSHOT1.1" true
"0.5.3-alpha.1.pre.0" true
"1.x.2" false
"1.2y" false
"1.y2" false
"1.y" false))
(let [v0 "1.0.0-SNAPSHOT"
v1 "1.0.0"
v2 "1.0.1-RC"
v3 "1.0.1"
ordered [v0 v1 v2 v3]]
(deftest t-version-sort
(is (= ordered (v/version-sort (shuffle ordered))))
(is (= (map v/version->seq ordered)
(v/version-seq-sort (map v/version->seq ordered)))))
(deftest t-version-compare
(is (pos? (v/version-compare v1 v0)))
(is (neg? (v/version-compare v0 v1)))
(is (zero? (v/version-compare v0 v0)))
(is (v/older? v0 v1))
(is (v/newer? v1 v0))
(is (v/older-or-equal? v0 v1))
(is (v/older-or-equal? v0 v0))
(is (v/newer-or-equal? v1 v0))
(is (v/newer-or-equal? v0 v0)))
(deftest t-version-seq-compare
(is (pos? (v/version-seq-compare
(v/version->seq v1)
(v/version->seq v0))))
(is (neg? (v/version-seq-compare
(v/version->seq v0)
(v/version->seq v1))))
(is (zero? (v/version-seq-compare
(v/version->seq v0)
(v/version->seq v0))))))
(deftest t-parse
(let [s "1.0.1", version (v/parse s)]
(is (= [[1 0 1]] (:version version)))
(is (= #{} (:qualifiers version)))
(is (not (:snapshot? version)))
(is (not (:qualified? version))))
(let [s "1.0.1-RC1-SNAPSHOT", version (v/parse s)]
(is (= [[1 0 1] [["rc" 1] "snapshot"]] (:version version)))
(is (= #{"rc" "snapshot"} (:qualifiers version)))
(is (:snapshot? version))
(is (:qualified? version)))
(let [s "1.0.1"]
(is (= (v/parse s) (v/parse (v/version->seq s))))))
(deftest t-version-and-qualifier-data
(is (= [1 0 1] (v/version-data "1.0.1-RC")))
(is (= ["rc"] (v/qualifier-data "1.0.1-RC"))))

View file

@ -1,22 +1,72 @@
(ns version-clj.split-test (ns version-clj.split-test
(:require [clojure.test :refer [deftest are is]] (:require #?(:clj [clojure.test :refer [deftest testing are is]]
:cljs [cljs.test :refer-macros [deftest testing are is]])
[version-clj.split :refer [version->seq]])) [version-clj.split :refer [version->seq]]))
(deftest t-split-once-sanity-check
(let [split-once @#'version-clj.split/split-once
rx #"(^|(?<=\d)|-)(?=alpha)"]
(are [in out] (= out (split-once rx in))
"1-alpha2.2" ["1" "alpha2.2"]
"alpha" ["" "alpha"]
"1alpha" ["1" "alpha"]
"0.0.3-alpha.8+oryOS.15" ["0.0.3" "alpha.8+oryOS.15"])))
(deftest t-split (deftest t-split
(are [version v] (= (version->seq version) v) (are [version v] (= v (version->seq version))
"1.0.0" [[1 0 0]] "1.0.0" [[1 0 0]]
"1.0" [[1 0]] "1.0" [[1 0]]
"1" [[1]] "1" [[1]]
"1a" [[1] ["a"]] "1a" [[1] ["a"]]
"1-a" [[1] ["a"]] "1-a" [[1] ["a"]]
"1.0.1-SNAPSHOT" [[1 0 1] ["snapshot"]] "1.0.1-SNAPSHOT" [[1 0 1] ["snapshot"]]
"1.0.1-alpha2" [[1 0 1] ["alpha" 2]] "1.0.1-alpha2" [[1 0 1] ["alpha" 2]]
"11.2.0.3.0" [[11 2 0 3 0]] "11.2.0.3.0" [[11 2 0 3 0]]
"1.0-1-0.2-RC" [[1 [0 1 0] 2] ["rc"]])) "1.0-1-0.2-RC" [[1 [0 1 0] 2] ["rc"]]
"1.0-612" [[1 0] [612]]
"alpha" [[] ["alpha"]]
"alpha-2" [[] ["alpha" 2]]
"1.alpha" [[1] ["alpha"]]
"1.alpha.2" [[1] ["alpha" 2]]
"1-alpha.2" [[1] ["alpha" 2]]
"1-alpha.2.2" [[1] ["alpha" 2 2]]
"1-alpha2.2" [[1] [["alpha" 2] 2]]
"1.alpha-1.0" [[1] ["alpha" [1 0]]]
"0.5.0-alpha.1" [[0 5 0] ["alpha" 1]]
"0.5.0-alpha.1" [[0 5 0] ["alpha" 1]]
"0.0.3-alpha.8+oryOS.15" [[0 0 3] ["alpha" [8 "+oryos"] 15]]
))
(deftest t-split-without-qualifiers
(testing "well-behaving."
(are [version] (= (version->seq version)
(version->seq version {:qualifiers {}}))
"1.0.0"
"1.0"
"1"
"1-a"
"1.0.1-SNAPSHOT"
"1.0.1-alpha2"
"11.2.0.3.0"
"1.0-1-0.2-RC"
"1-alpha.2"
"1-alpha.2.2"
"1-alpha2.2"
"0.5.0-alpha.1"
"0.5.0-alpha.1"
"0.0.3-alpha.8+oryOS.15"))
(testing "deviants."
(are [version v] (= v (version->seq version {:qualifiers {}}))
"alpha" [["alpha"]]
"alpha-2" [["alpha"] [2]]
"1a" [[1 "a"]]
"1.alpha" [[1 "alpha"]]
"1.alpha.2" [[1 "alpha" 2]]
"1.alpha-1.0" [[1 ["alpha" 1] 0]])))
(deftest t-split-with-large-number (deftest t-split-with-large-number
(is (= (version->seq "0.0.1-20141002100138") (is (= [[0 0 1] [20141002100138]]
[[0 0 1] [20141002100138]])) (version->seq "0.0.1-20141002100138")))
#?(:clj #?(:clj
(let [v (str Long/MAX_VALUE "12345")] (let [v (str Long/MAX_VALUE "12345")]
(is (= (version->seq v) [[(bigint v)]]))))) (is (= (version->seq v) [[(bigint v)]])))))

View file

@ -0,0 +1,11 @@
(ns tasks
"This is task ns docstring.")
(defn -main
"Main docstring"
[& args]
args)
(defn foo
"Foo docstring"
[])

View file

@ -0,0 +1,51 @@
(ns babashka.bb-edn-test
(:require
[babashka.fs :as fs]
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
[clojure.string :as str]
[clojure.test :as test :refer [deftest is testing]]))
(defn bb [& args]
(edn/read-string
{:readers *data-readers*
:eof nil}
(apply test-utils/bb nil (map str args))))
(defmacro with-config [cfg & body]
`(let [temp-dir# (fs/create-temp-dir)
bb-edn-file# (fs/file temp-dir# "bb.edn")]
(binding [*print-meta* true]
(spit bb-edn-file# ~cfg))
(binding [test-utils/*bb-edn-path* (str bb-edn-file#)]
~@body)))
(deftest doc-test
(with-config {:paths ["test-resources/task_scripts"]}
(is (str/includes? (apply test-utils/bb nil
(map str ["doc" "tasks"]))
"This is task ns docstring."))
(is (str/includes? (apply test-utils/bb nil
(map str ["doc" "tasks/foo"]))
"Foo docstring"))
(is (str/includes? (apply test-utils/bb nil
(map str ["doc" "tasks/-main"]))
"Main docstring"))))
(deftest deps-test
(with-config '{:deps {medley/medley {:mvn/version "1.3.0"}}}
(is (= '{1 {:id 1}, 2 {:id 2}}
(bb "-e" "(require 'medley.core)" "-e" "(medley.core/index-by :id [{:id 1} {:id 2}])"))))
(testing "--classpath option overrides bb.edn"
(with-config '{:deps {medley/medley {:mvn/version "1.3.0"}}}
(is (= "src"
(bb "-cp" "src" "-e" "(babashka.classpath/get-classpath)"))))))
;; TODO:
;; Do we want to support the same parsing as the clj CLI?
;; Or do we want `--aliases :foo:bar`
;; Let's wait for a good use case
#_(deftest alias-deps-test
(with-config '{:aliases {:medley {:deps {medley/medley {:mvn/version "1.3.0"}}}}}
(is (= '{1 {:id 1}, 2 {:id 2}}
(bb "-A:medley" "-e" "(require 'medley.core)" "-e" "(medley.core/index-by :id [{:id 1} {:id 2}])")))))

View file

@ -195,7 +195,7 @@
:features #{:bb}}) :features #{:bb}})
nrepl-opts)] nrepl-opts)]
(reset! server-state server)) (reset! server-state server))
(let [pb (ProcessBuilder. ["./bb" "--nrepl-server" "0.0.0.0:1668"]) (let [pb (ProcessBuilder. ["./bb" "nrepl-server" "0.0.0.0:1668"])
_ (.redirectError pb ProcessBuilder$Redirect/INHERIT) _ (.redirectError pb ProcessBuilder$Redirect/INHERIT)
;; _ (.redirectOutput pb ProcessBuilder$Redirect/INHERIT) ;; _ (.redirectOutput pb ProcessBuilder$Redirect/INHERIT)
;; env (.environment pb) ;; env (.environment pb)

View file

@ -51,7 +51,7 @@
(vreset! common/ctx ctx) (vreset! common/ctx ctx)
(start-repl! "0.0.0.0:1666" ctx)) (start-repl! "0.0.0.0:1666" ctx))
(do (vreset! server-process (do (vreset! server-process
(p/process ["./bb" "--socket-repl" "localhost:1666"])) (p/process ["./bb" "socket-repl" "localhost:1666"]))
(w/wait-for-port "localhost" 1666))) (w/wait-for-port "localhost" 1666)))
(Thread/sleep 50) (Thread/sleep 50)
(is (socket-command "(+ 1 2 3)" "user=> 6")) (is (socket-command "(+ 1 2 3)" "user=> 6"))

View file

@ -7,21 +7,10 @@
[clojure.java.io :as io] [clojure.java.io :as io]
[clojure.java.shell :refer [sh]] [clojure.java.shell :refer [sh]]
[clojure.string :as str] [clojure.string :as str]
[clojure.test :as test :refer [deftest is testing *report-counters*]] [clojure.test :as test :refer [deftest is testing]]
[flatland.ordered.map :refer [ordered-map]] [flatland.ordered.map :refer [ordered-map]]
[sci.core :as sci])) [sci.core :as sci]))
(defmethod clojure.test/report :begin-test-var [m]
(println "===" (-> m :var meta :name))
(println))
(defmethod clojure.test/report :end-test-var [_m]
(let [{:keys [:fail :error]} @*report-counters*]
(when (and (= "true" (System/getenv "BABASHKA_FAIL_FAST"))
(or (pos? fail) (pos? error)))
(println "=== Failing fast")
(System/exit 1))))
(defn bb [input & args] (defn bb [input & args]
(edn/read-string (edn/read-string
{:readers *data-readers* {:readers *data-readers*
@ -363,16 +352,7 @@
(is (.exists f2)) (is (.exists f2))
(let [v (bb nil "-f" (.getPath (io/file "test-resources" "babashka" "glob.clj")))] (let [v (bb nil "-f" (.getPath (io/file "test-resources" "babashka" "glob.clj")))]
(is (vector? v)) (is (vector? v))
(is (.exists (io/file (first v)))))) (is (.exists (io/file (first v)))))))
(testing "reify can handle multiple classes at once"
(is (true? (bb nil "
(def filter-obj (reify java.io.FileFilter
(accept [this f] (prn (.getPath f)) true)
java.io.FilenameFilter
(accept [this f name] (prn name) true)))
(def s1 (with-out-str (.listFiles (clojure.java.io/file \".\") filter-obj)))
(def s2 (with-out-str (.list (clojure.java.io/file \".\") filter-obj)))
(and (pos? (count s1)) (pos? (count s2)))")))))
(deftest future-print-test (deftest future-print-test
(testing "the root binding of sci/*out*" (testing "the root binding of sci/*out*"
@ -574,7 +554,12 @@
(deftest var-print-method-test (deftest var-print-method-test
(when test-utils/native? (when test-utils/native?
(is (bb nil "(defmethod print-method sci.lang.IVar [o w] (.write w (str :foo (symbol o)))) (def x 1) (= \":foouser/x\" (pr-str #'x))")))) (is (bb nil "(defmethod print-method sci.lang.IVar [o w] (.write w (str :foo (symbol o)))) (def x 1) (= \":foouser/x\" (pr-str #'x))"))
(is (= :foouser/x (bb nil "(defmethod print-method sci.lang.IVar [o w] (.write w (str :foo (symbol o)))) (def x 1)")))))
(deftest stdout-interop-test
(when test-utils/native?
(is (= 'Something (bb nil "(.print (System/out) \"Something\")")))))
;;;; Scratch ;;;; Scratch

View file

@ -0,0 +1,80 @@
(ns babashka.proxy-test
(:require
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
[clojure.test :as test :refer [deftest is]]))
(defn bb [& args]
(edn/read-string
{:readers *data-readers*
:eof nil}
(apply test-utils/bb nil (map str args))))
(def code
'(do
(require '[clojure.core.protocols])
(require '[clojure.datafy :as d])
(defn auto-deref
"If value implements IDeref, deref it, otherwise return original."
[x]
(if (instance? clojure.lang.IDeref x)
@x
x))
(defn proxy-deref-map
{:added "1.0"}
[m]
(proxy [clojure.lang.APersistentMap clojure.lang.IMeta clojure.lang.IObj clojure.core.protocols.Datafiable]
[]
(iterator []
::TODO)
(containsKey [k] (contains? m k))
(entryAt [k] (when (contains? m k) (proxy [clojure.lang.AMapEntry] []
(key [] k)
(val [] (auto-deref (get m k))))))
(valAt ([k] (auto-deref (get m k)))
([k default] (auto-deref (get m k default))))
(cons [v] (proxy-deref-map (conj m v)))
(count [] (count m))
(assoc [k v] (proxy-deref-map (assoc m k v)))
(without [k] (proxy-deref-map (dissoc m k)))
(seq [] (map (fn [[k v]](proxy [clojure.lang.AMapEntry] []
(key [] k)
(val [] (auto-deref (get m k))))) m))
(withMeta [md] (proxy-deref-map (with-meta m md)))
(meta [] (meta m))
(datafy [] {:datafied true})))
(let [m (proxy-deref-map
{:a (delay 1)
:b (delay 2)
:c 3})]
[(:a m)
(:b m)
(:c m)
(contains? m :c)
(find m :c)
(-> (conj m [:d (delay 5)])
:d)
(count m)
(-> (assoc m :d (delay 5))
:d)
(-> (dissoc m :a)
(contains? :a))
(seq m)
(meta (with-meta m {:a 1}))
(d/datafy m)
(instance? clojure.lang.APersistentMap m)
(instance? java.io.FilenameFilter m)
,])))
(require 'clojure.pprint)
(deftest APersistentMap-proxy-test
(is (= [1 2 3 true [:c 3]
5 3 5 false
'([:a 1] [:b 2] [:c 3])
{:a 1}
{:datafied true}
true
false]
(bb (with-out-str (clojure.pprint/pprint code))))))

View file

@ -0,0 +1,67 @@
(ns babashka.reify-test
(:require
[babashka.test-utils :as test-utils]
[clojure.edn :as edn]
[clojure.test :as test :refer [deftest is testing]]))
(defn bb [input & args]
(edn/read-string
{:readers *data-readers*
:eof nil}
(apply test-utils/bb (when (some? input) (str input)) (map str args))))
(deftest file-filter-test
(is (true? (bb nil "
(def filter-obj (reify java.io.FileFilter
(accept [this f] (prn (.getPath f)) true)))
(def filename-filter-obj
(reify java.io.FilenameFilter
(accept [this f name] (prn name) true)))
(def s1 (with-out-str (.listFiles (clojure.java.io/file \".\") filter-obj)))
(def s2 (with-out-str (.listFiles (clojure.java.io/file \".\") filename-filter-obj)))
(and (pos? (count s1)) (pos? (count s2)))"))))
(deftest reify-multiple-arities-test
(testing "ILookup"
(is (= ["->:foo" 10]
(bb nil "
(def m (reify clojure.lang.ILookup
(valAt [this x] (str \"->\" x))
(valAt [this x y] y)))
[(:foo m) (:foo m 10)]"))))
(testing "IFn"
(is (= [:yo :three :six :twelve :eighteen :nineteen 19]
(bb nil "
(def m (reify clojure.lang.IFn
(invoke [this] :yo)
(invoke [this _ _ _] :three)
(invoke [this _ _ _ _ _ _] :six)
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _] :twelve)
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _] :eighteen)
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _] :nineteen)
(applyTo [this args] (last args))))
[
(m)
(m 1 2 3)
(m 1 2 3 4 5 6)
(m 1 2 3 4 5 6 1 2 3 4 5 6)
(m 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6)
(m 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1)
(apply m (range 20))
]")))))
(deftest reify-object
(testing "toString"
(is (= ":foo"
(bb nil "
(def m (reify Object
(toString [_] (str :foo))))
(str m)
"))))
(testing "Hashcode still works when only overriding toString"
(is (number?
(bb nil "
(def m (reify Object
(toString [_] (str :foo))))
(hash m)
")))))

View file

@ -2,14 +2,33 @@
(:require (:require
[babashka.impl.classpath :as cp] [babashka.impl.classpath :as cp]
[babashka.main :as main] [babashka.main :as main]
[me.raynes.conch :refer [let-programs] :as sh] [babashka.process :as p]
[clojure.edn :as edn]
[clojure.test :as test :refer [*report-counters*]]
[sci.core :as sci] [sci.core :as sci]
[sci.impl.vars :as vars])) [sci.impl.vars :as vars]))
(set! *warn-on-reflection* true) (set! *warn-on-reflection* true)
(def ^:dynamic *bb-edn-path* nil)
(defmethod clojure.test/report :begin-test-var [m]
(println "===" (-> m :var meta :name))
(println))
(defmethod clojure.test/report :end-test-var [_m]
(let [{:keys [:fail :error]} @*report-counters*]
(when (and (= "true" (System/getenv "BABASHKA_FAIL_FAST"))
(or (pos? fail) (pos? error)))
(println "=== Failing fast")
(System/exit 1))))
(defn bb-jvm [input-or-opts & args] (defn bb-jvm [input-or-opts & args]
(reset! cp/cp-state nil) (reset! cp/cp-state nil)
(reset! main/env {})
(if-let [path *bb-edn-path*]
(vreset! main/bb-edn (edn/read-string (slurp path)))
(vreset! main/bb-edn nil))
(let [os (java.io.StringWriter.) (let [os (java.io.StringWriter.)
es (if-let [err (:err input-or-opts)] es (if-let [err (:err input-or-opts)]
err (java.io.StringWriter.)) err (java.io.StringWriter.))
@ -30,26 +49,33 @@
(if (string? input-or-opts) (if (string? input-or-opts)
(with-in-str input-or-opts (apply main/main args)) (with-in-str input-or-opts (apply main/main args))
(apply main/main args)))] (apply main/main args)))]
;; (prn :err (str es))
(if (zero? res) (if (zero? res)
(str os) (str os)
(throw (ex-info (str es) (do
{:stdout (str os) (println (str os))
:stderr (str es)}))))) (throw (ex-info (str es)
{:stdout (str os)
:stderr (str es)}))))))
(finally (finally
(when (string? input-or-opts) (vars/bindRoot sci/in *in*)) (when (string? input-or-opts) (vars/bindRoot sci/in *in*))
(vars/bindRoot sci/out *out*) (vars/bindRoot sci/out *out*)
(vars/bindRoot sci/err *err*))))) (vars/bindRoot sci/err *err*)))))
(defn bb-native [input & args] (defn bb-native [input & args]
(let-programs [bb "./bb"] (let [res (p/process (into ["./bb"] args)
(try (if input (cond-> {:in input
(apply bb (conj (vec args) :out :string
{:in input})) :err :string}
(apply bb args)) *bb-edn-path*
(catch Exception e (assoc
(let [d (ex-data e) :env (assoc (into {} (System/getenv))
err-msg (or (:stderr (ex-data e)) "")] "BABASHKA_EDN" *bb-edn-path*))))
(throw (ex-info err-msg d))))))) res (deref res)
exit (:exit res)
error? (pos? exit)]
(if error? (throw (ex-info (or (:err res) "") {}))
(:out res))))
(def bb (def bb
(case (System/getenv "BABASHKA_TEST_ENV") (case (System/getenv "BABASHKA_TEST_ENV")

View file

@ -1,7 +1,6 @@
(ns babashka.uberjar-test (ns babashka.uberjar-test
(:require (:require
[babashka.test-utils :as tu] [babashka.test-utils :as tu]
[clojure.edn :as edn]
[clojure.string :as str] [clojure.string :as str]
[clojure.test :as t :refer [deftest is testing]])) [clojure.test :as t :refer [deftest is testing]]))
@ -10,7 +9,7 @@
path (.getPath tmp-file)] path (.getPath tmp-file)]
(.deleteOnExit tmp-file) (.deleteOnExit tmp-file)
(testing "uberjar" (testing "uberjar"
(tu/bb nil "--classpath" "test-resources/babashka/uberjar/src" "-m" "my.main-main" "--uberjar" path) (tu/bb nil "uberjar" path "--classpath" "test-resources/babashka/uberjar/src" "-m" "my.main-main")
(is (= "(\"1\" \"2\" \"3\" \"4\")\n" (is (= "(\"1\" \"2\" \"3\" \"4\")\n"
(tu/bb nil "--jar" path "1" "2" "3" "4"))) (tu/bb nil "--jar" path "1" "2" "3" "4")))
(is (= "(\"1\" \"2\" \"3\" \"4\")\n" (is (= "(\"1\" \"2\" \"3\" \"4\")\n"
@ -25,5 +24,5 @@
(let [tmp-file (java.io.File/createTempFile "uber" ".jar") (let [tmp-file (java.io.File/createTempFile "uber" ".jar")
path (.getPath tmp-file)] path (.getPath tmp-file)]
(.deleteOnExit tmp-file) (.deleteOnExit tmp-file)
(tu/bb nil "--classpath" "test-resources/babashka/uberjar/src" "--uberjar" path) (tu/bb nil "uberjar" path "--classpath" "test-resources/babashka/uberjar/src")
(is (str/includes? (tu/bb "(+ 1 2 3)" path) "6"))))) (is (str/includes? (tu/bb "(+ 1 2 3)" path) "6")))))