Merge branch 'master' into clojure.data.xml
This commit is contained in:
commit
90f10061b3
61 changed files with 1527 additions and 1107 deletions
3
.carve_ignore
Normal file
3
.carve_ignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
babashka.impl.clojure.stacktrace/root-cause
|
||||
babashka.impl.classes/generate-reflection-file
|
||||
babashka.main/-main
|
||||
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
working_directory: ~/repo
|
||||
environment:
|
||||
LEIN_ROOT: "true"
|
||||
# GRAALVM_HOME: /home/circleci/graalvm-ce-java8-19.3.0
|
||||
BABASHKA_PLATFORM: linux # could be used in jar name
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
|
|
@ -34,18 +34,6 @@ jobs:
|
|||
name: Install lsof
|
||||
command: |
|
||||
sudo apt-get install lsof
|
||||
# - run:
|
||||
# name: Download GraalVM
|
||||
# command: |
|
||||
# cd ~
|
||||
# if ! [ -d graalvm-ce-java8-19.3.0 ]; then
|
||||
# curl -O -sL https://github.com/oracle/graal/releases/download/vm-19.2.0/graalvm-ce-linux-amd64-19.2.0.tar.gz
|
||||
# tar xzf graalvm-ce-linux-amd64-19.2.0.tar.gz
|
||||
# fi
|
||||
# - run:
|
||||
# name: Install GraalVM SSL libs
|
||||
# command: |
|
||||
# .circleci/script/graalvm_ssl
|
||||
- run:
|
||||
name: Run JVM tests
|
||||
command: |
|
||||
|
|
@ -58,6 +46,16 @@ jobs:
|
|||
name: Run as lein command
|
||||
command: |
|
||||
.circleci/script/lein
|
||||
- run:
|
||||
name: Create uberjar
|
||||
command: |
|
||||
mkdir -p /tmp/release
|
||||
lein do clean, uberjar
|
||||
VERSION=$(cat resources/BABASHKA_VERSION)
|
||||
cp target/babashka-$VERSION-standalone.jar /tmp/release/babashka-$VERSION-standalone.jar
|
||||
- store_artifacts:
|
||||
path: /tmp/release
|
||||
destination: release
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
|
|
@ -117,6 +115,7 @@ jobs:
|
|||
name: Run tests
|
||||
command: |
|
||||
script/test
|
||||
script/run_lib_tests
|
||||
# - run:
|
||||
# name: Performance report
|
||||
# command: |
|
||||
|
|
@ -133,6 +132,10 @@ jobs:
|
|||
- store_artifacts:
|
||||
path: /tmp/release
|
||||
destination: release
|
||||
- run:
|
||||
name: Publish artifact link to Slack
|
||||
command: |
|
||||
./bb .circleci/script/publish_artifact.clj
|
||||
mac:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
|
|
@ -180,6 +183,7 @@ jobs:
|
|||
name: Run tests
|
||||
command: |
|
||||
script/test
|
||||
script/run_lib_tests
|
||||
# - run:
|
||||
# name: Performance report
|
||||
# command: |
|
||||
|
|
@ -196,6 +200,10 @@ jobs:
|
|||
- store_artifacts:
|
||||
path: /tmp/release
|
||||
destination: release
|
||||
- run:
|
||||
name: Publish artifact link to Slack
|
||||
command: |
|
||||
./bb .circleci/script/publish_artifact.clj
|
||||
deploy:
|
||||
docker:
|
||||
- image: circleci/clojure:lein-2.8.1
|
||||
|
|
|
|||
19
.circleci/script/publish_artifact.clj
Executable file
19
.circleci/script/publish_artifact.clj
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
(require '[clojure.java.shell :refer [sh]]
|
||||
'[cheshire.core :refer [generate-string]])
|
||||
|
||||
(def channel "#babashka_circleci_builds")
|
||||
#_(def channel "#_test")
|
||||
|
||||
(def text (format "[%s - %s@%s]: https://%s-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.61-SNAPSHOT-%s-amd64.zip"
|
||||
(System/getenv "BABASHKA_PLATFORM")
|
||||
(System/getenv "CIRCLE_BRANCH")
|
||||
(System/getenv "CIRCLE_SHA1")
|
||||
(System/getenv "CIRCLE_BUILD_NUM")
|
||||
(System/getenv "BABASHKA_PLATFORM")))
|
||||
|
||||
(def slack-hook-url (System/getenv "SLACK_HOOK_URL"))
|
||||
(when slack-hook-url
|
||||
(let [json (generate-string {:username "borkdude"
|
||||
:channel channel
|
||||
:text text})]
|
||||
(sh "curl" "-X" "POST" "-H" "Content-Type: application/json" "-d" json slack-hook-url)))
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -9,7 +9,7 @@ assignees: ''
|
|||
|
||||
**version**
|
||||
|
||||
[ Please specify which version of babashka you're using. You can find this with `babashka --version`. The documentation on the master branch may be ahead of the most released version. You can check the docs for your version by going to cljdoc. ]
|
||||
[ Please specify which version of babashka you're using. You can find this with `babashka --version`. The documentation on the master branch may be ahead of the most released version. ]
|
||||
|
||||
**platform**
|
||||
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -15,4 +15,4 @@ pom.xml.asc
|
|||
!java/src/babashka/impl/LockFix.class
|
||||
!test-resources/babashka/src_for_classpath_test/foo.jar
|
||||
.cpcache
|
||||
deps.edn
|
||||
reflection.json
|
||||
|
|
|
|||
11
CHANGES.md
Normal file
11
CHANGES.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Changes
|
||||
|
||||
## Breaking changes
|
||||
|
||||
## v0.0.44 - 0.0.45
|
||||
- #173: Rename `*in*` to `*input*` (in the `user` namespace). The reason for
|
||||
this is that itt shadowed `clojure.core/*in*` when used unqualified.
|
||||
|
||||
## v0.0.43
|
||||
- #160: Add support for `java.lang.ProcessBuilder`. See docs. This replaces the
|
||||
`conch` namespace.
|
||||
353
README.md
353
README.md
|
|
@ -1,18 +1,24 @@
|
|||
# babashka
|
||||
<img src="logo/babashka.svg" width="425px">
|
||||
|
||||
[](https://circleci.com/gh/borkdude/babashka/tree/master)
|
||||
[](https://clojars.org/borkdude/babashka)
|
||||
[](https://cljdoc.org/d/borkdude/babashka/CURRENT)
|
||||
[](https://app.slack.com/client/T03RZGPFR/CLX41ASCS)
|
||||
|
||||
<!-- [](https://cljdoc.org/d/borkdude/babashka/CURRENT) -->
|
||||
|
||||
A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash.
|
||||
|
||||
<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>
|
||||
—
|
||||
<a href="https://github.com/laheadle">@laheadle</a> on Clojurians Slack
|
||||
</blockquote>
|
||||
|
||||
## Quickstart
|
||||
|
||||
``` shellsession
|
||||
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install)
|
||||
$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *in*)'
|
||||
$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)'
|
||||
("doc" "resources" "sci" "script" "src" "target" "test")
|
||||
bb took 4ms.
|
||||
```
|
||||
|
|
@ -41,45 +47,42 @@ Non-goals:
|
|||
* Provide a mixed Clojure/bash DSL (see portability).
|
||||
* Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them.
|
||||
|
||||
Reasons why babashka may not be the right fit for your use case:
|
||||
|
||||
- It uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci
|
||||
implements only a subset of Clojure and is not as performant as compiled code.
|
||||
- External libraries are not available (although you may use `load-file` for
|
||||
loading external scripts).
|
||||
Babashka uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci
|
||||
implements a subset of Clojure and is not as performant as compiled code. If your script is taking more than a few seconds, Clojure on the JVM may be a better fit.
|
||||
|
||||
Read more about the differences with Clojure [here](#differences-with-clojure).
|
||||
|
||||
## Status
|
||||
|
||||
Experimental. Breaking changes are expected to happen at this phase.
|
||||
Experimental. Breaking changes are expected to happen at this phase. Keep an eye
|
||||
on [CHANGES.md](CHANGES.md) for a list of breaking changes.
|
||||
|
||||
## Examples
|
||||
|
||||
``` shellsession
|
||||
$ ls | bb -i '*in*'
|
||||
["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"]
|
||||
$ ls | bb -i '*input*'
|
||||
["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "resources" "script" "src" "target" "test"]
|
||||
|
||||
$ ls | bb -i '(count *in*)'
|
||||
$ ls | bb -i '(count *input*)'
|
||||
12
|
||||
|
||||
$ bb '(vec (dedupe *in*))' <<< '[1 1 1 1 2]'
|
||||
$ bb '(vec (dedupe *input*))' <<< '[1 1 1 1 2]'
|
||||
[1 2]
|
||||
|
||||
$ bb '(filterv :foo *in*)' <<< '[{:foo 1} {:bar 2}]'
|
||||
$ bb '(filterv :foo *input*)' <<< '[{:foo 1} {:bar 2}]'
|
||||
[{:foo 1}]
|
||||
|
||||
$ bb '(#(+ %1 %2 %3) 1 2 *in*)' <<< 3
|
||||
$ bb '(#(+ %1 %2 %3) 1 2 *input*)' <<< 3
|
||||
6
|
||||
|
||||
$ ls | bb -i '(filterv #(re-find #"reflection" %) *in*)'
|
||||
["reflection.json"]
|
||||
$ ls | bb -i '(filterv #(re-find #"README" %) *input*)'
|
||||
["README.md"]
|
||||
|
||||
$ bb '(run! #(shell/sh "touch" (str "/tmp/test/" %)) (range 100))'
|
||||
$ ls /tmp/test | bb -i '*in*'
|
||||
$ ls /tmp/test | bb -i '*input*'
|
||||
["0" "1" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "2" "20" "21" ...]
|
||||
|
||||
$ bb -O '(repeat "dude")' | bb --stream '(str *in* "rino")' | bb -I '(take 3 *in*)'
|
||||
$ bb -O '(repeat "dude")' | bb --stream '(str *input* "rino")' | bb -I '(take 3 *input*)'
|
||||
("duderino" "duderino" "duderino")
|
||||
```
|
||||
|
||||
|
|
@ -128,27 +131,31 @@ You may also download a binary from [Github](https://github.com/borkdude/babashk
|
|||
|
||||
``` shellsession
|
||||
Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose]
|
||||
[ ( --classpath | -cp ) <cp> ] [ ( --main | -m ) <main-namespace> ]
|
||||
( -e <expression> | -f <file> | --repl | --socket-repl [<host>:]<port> )
|
||||
[ ( --classpath | -cp ) <cp> ] [ --uberscript <file> ]
|
||||
[ ( --main | -m ) <main-namespace> | -e <expression> | -f <file> |
|
||||
--repl | --socket-repl [<host>:]<port> ]
|
||||
[ arg* ]
|
||||
|
||||
Options:
|
||||
|
||||
--help, -h or -? Print this help text.
|
||||
--version Print the current version of babashka.
|
||||
-i Bind *in* to a lazy seq of lines from stdin.
|
||||
-I Bind *in* to a lazy seq of EDN values from stdin.
|
||||
-o Write lines to stdout.
|
||||
-O Write EDN values to stdout.
|
||||
--verbose Print entire stacktrace in case of exception.
|
||||
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *in* becomes a single value per iteration.
|
||||
-e, --eval <expr> Evaluate an expression.
|
||||
-f, --file <path> Evaluate a file.
|
||||
-cp, --classpath Classpath to use.
|
||||
-m, --main <ns> Call the -main function from namespace with args.
|
||||
--repl Start REPL
|
||||
--socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
||||
--time Print execution time before exiting.
|
||||
--help, -h or -? Print this help text.
|
||||
--version Print the current version of babashka.
|
||||
|
||||
-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.
|
||||
--verbose Print entire stacktrace in case of exception.
|
||||
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration.
|
||||
--uberscript <file> Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file.
|
||||
|
||||
-e, --eval <expr> Evaluate an expression.
|
||||
-f, --file <path> Evaluate a file.
|
||||
-cp, --classpath Classpath to use.
|
||||
-m, --main <ns> Call the -main function from namespace with args.
|
||||
--repl Start REPL
|
||||
--socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
||||
--time Print execution time before exiting.
|
||||
|
||||
If neither -e, -f, or --socket-repl are specified, then the first argument that is not parsed as a option is treated as a file if it exists, or as an expression otherwise.
|
||||
Everything after that is bound to *command-line-args*.
|
||||
|
|
@ -165,40 +172,22 @@ enumerated explicitly.
|
|||
- `clojure.set` aliased as `set`
|
||||
- `clojure.edn` aliased as `edn`:
|
||||
- `read-string`
|
||||
- `clojure.java.shell` aliases as `shell`:
|
||||
- `sh`
|
||||
- `clojure.java.shell` aliases as `shell`
|
||||
- `clojure.java.io` aliased as `io`:
|
||||
- `as-relative-path`, `copy`, `delete-file`, `file`
|
||||
- `as-relative-path`, `as-url`, `copy`, `delete-file`, `file`, `input-stream`,
|
||||
`make-parents`, `output-stream`, `reader`, `resource`, `writer`
|
||||
- `clojure.main`: `repl`
|
||||
- [`clojure.core.async`](https://clojure.github.io/core.async/) aliased as
|
||||
`async`. The `alt` and `go` macros are not available but `alts!!` does work as
|
||||
it is a function.
|
||||
- [`me.raynes.conch.low-level`](https://github.com/clj-commons/conch#low-level-usage)
|
||||
aliased as `conch`
|
||||
- `clojure.stacktrace`
|
||||
- [`clojure.tools.cli`](https://github.com/clojure/tools.cli) aliased as `tools.cli`
|
||||
- [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv`
|
||||
- [`cheshire.core`](https://github.com/dakrone/cheshire) aliased as `json`
|
||||
|
||||
The following Java classes are available:
|
||||
A selection of java classes are available, see `babashka/impl/classes.clj`.
|
||||
|
||||
- `ArithmeticException`
|
||||
- `AssertionError`
|
||||
- `Boolean`
|
||||
- `Class`
|
||||
- `Double`
|
||||
- `Exception`
|
||||
- `clojure.lang.ExceptionInfo`
|
||||
- `Integer`
|
||||
- `java.io.File`
|
||||
- `java.nio.Files`
|
||||
- `java.util.regex.Pattern`
|
||||
- `String`
|
||||
- `System`
|
||||
- `Thread`
|
||||
|
||||
More classes can be added by request. See `reflection.json` and the `:classes`
|
||||
option in `main.clj`.
|
||||
|
||||
Babashka supports `import` : `(import clojure.lang.ExceptionInfo)`.
|
||||
Babashka supports `import`: `(import clojure.lang.ExceptionInfo)`.
|
||||
|
||||
Babashka supports a subset of the `ns` form where you may use `:require` and `:import`:
|
||||
|
||||
|
|
@ -211,11 +200,48 @@ Babashka supports a subset of the `ns` form where you may use `:require` and `:i
|
|||
For the unsupported parts of the ns form, you may use [reader
|
||||
conditionals](#reader-conditionals) to maintain compatibility with JVM Clojure.
|
||||
|
||||
Special vars:
|
||||
### Input and output flags
|
||||
|
||||
- `*in*`: contains the input read from stdin. EDN by default, multiple lines of
|
||||
text with the `-i` option, or multiple EDN values with the `-I` option.
|
||||
- `*command-line-args*`: contain the command line args
|
||||
In one-liners the `*input*` value may come in handy. It contains the input read from stdin as EDN by default. If you want to read in text, use the `-i` flag, which binds `*input*` to a lazy seq of lines of text. If you want to read multiple EDN values, use the `-I` flag. The `-o` option prints the result as lines of text. The `-O` option prints the result as lines of EDN values.
|
||||
|
||||
The following table illustrates the combination of options for commands of the form
|
||||
|
||||
echo "{{Input}}" | bb {{Input flags}} {{Output flags}} "*input*"
|
||||
|
||||
| Input | Input flags | Output flag | `*input*` | Output |
|
||||
|----------------|-------------|-------------|---------------|----------|
|
||||
| `{:a 1}` <br> `{:a 2}` | | | `{:a 1}` | `{:a 1}` |
|
||||
| hello <br> bye | `-i` | | `("hello" "bye")` | `("hello" "bye")` |
|
||||
| hello <br> bye | `-i` | `-o` | `("hello" "bye")` | hello <br> bye |
|
||||
| `{:a 1}` <br> `{:a 2}` | `-I` | | `({:a 1} {:a 2})` | `({:a 1} {:a 2})` |
|
||||
| `{:a 1}` <br> `{:a 2}` | `-I` | `-O` | `({:a 1} {:a 2})` | `{:a 1}` <br> `{:a 2}` |
|
||||
|
||||
When combined with the `--stream` option, the expression is executed for each value in the input:
|
||||
|
||||
``` clojure
|
||||
$ echo '{:a 1} {:a 2}' | bb --stream '*input*'
|
||||
{:a 1}
|
||||
{:a 2}
|
||||
```
|
||||
|
||||
### Current file path
|
||||
|
||||
The var `*file*` contains the full path of the file that is currently being
|
||||
executed:
|
||||
|
||||
``` shellsession
|
||||
$ cat example.clj
|
||||
(prn *file*)
|
||||
|
||||
$ bb example.clj
|
||||
"/Users/borkdude/example.clj"
|
||||
```
|
||||
|
||||
### Command-line arguments
|
||||
|
||||
Command-line arguments can be retrieved using `*command-line-args*`.
|
||||
|
||||
### Additional functions
|
||||
|
||||
Additionally, babashka adds the following functions:
|
||||
|
||||
|
|
@ -329,7 +355,7 @@ export BABASHKA_PRELOADS
|
|||
Note that you can concatenate multiple expressions. Now you can use these functions in babashka:
|
||||
|
||||
``` shellsession
|
||||
$ bb '(-> (foo *in*) bar)' <<< 1
|
||||
$ bb '(-> (foo *input*) bar)' <<< 1
|
||||
6
|
||||
```
|
||||
|
||||
|
|
@ -339,7 +365,7 @@ You can also preload an entire file using `load-file`:
|
|||
export BABASHKA_PRELOADS='(load-file "my_awesome_prelude.clj")'
|
||||
```
|
||||
|
||||
Note that `*in*` is not available in preloads.
|
||||
Note that `*input*` is not available in preloads.
|
||||
|
||||
## Classpath
|
||||
|
||||
|
|
@ -361,10 +387,10 @@ Note that you can use the `clojure` tool to produce classpaths and download depe
|
|||
``` shellsession
|
||||
$ cat deps.edn
|
||||
{:deps
|
||||
{my_gist_script
|
||||
{:git/url "https://gist.github.com/borkdude/263b150607f3ce03630e114611a4ef42"
|
||||
:sha "cfc761d06dfb30bb77166b45d439fe8fe54a31b8"}}}
|
||||
|
||||
{my_gist_script
|
||||
{:git/url "https://gist.github.com/borkdude/263b150607f3ce03630e114611a4ef42"
|
||||
:sha "cfc761d06dfb30bb77166b45d439fe8fe54a31b8"}}
|
||||
:aliases {:my-script {:main-opts ["-m" "my-gist-script"]}}}
|
||||
|
||||
$ CLASSPATH=$(clojure -Spath)
|
||||
$ bb --classpath "$CLASSPATH" --main my-gist-script
|
||||
|
|
@ -381,6 +407,57 @@ $ bb "(my-gist-script/-main)"
|
|||
Hello from gist script!
|
||||
```
|
||||
|
||||
### Deps.clj
|
||||
|
||||
The [`deps.clj`](https://github.com/borkdude/deps.clj/) script can be used to work with `deps.edn`-based projects:
|
||||
|
||||
``` shell
|
||||
$ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}}"
|
||||
Hello from gist script!
|
||||
```
|
||||
|
||||
Create these aliases for brevity:
|
||||
|
||||
``` shell
|
||||
$ alias bbk='deps.clj -Scommand "bb -cp {{classpath}} {{main-opts}}"'
|
||||
$ alias babashka='rlwrap deps.clj -Scommand "bb -cp {{classpath}} {{main-opts}}"'
|
||||
$ bbk -A:my-script
|
||||
Hello from gist script!
|
||||
$ babashka
|
||||
Babashka v0.0.58 REPL.
|
||||
Use :repl/quit or :repl/exit to quit the REPL.
|
||||
Clojure rocks, Bash reaches.
|
||||
|
||||
user=> (require '[my-gist-script :as mgs])
|
||||
nil
|
||||
user=> (mgs/-main)
|
||||
Hello from gist script!
|
||||
nil
|
||||
```
|
||||
|
||||
## Uberscript
|
||||
|
||||
The `--uberscript` option collects the expressions in
|
||||
`BABASHKA_PRELOADS`, the command line expression or file, the main entrypoint
|
||||
and all required namespaces from the classpath into a single file. This can be
|
||||
convenient for debugging and deployment.
|
||||
|
||||
Given the `deps.edn` from above:
|
||||
|
||||
``` clojure
|
||||
$ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}} --uberscript my-script.clj"
|
||||
|
||||
$ cat my-script.clj
|
||||
(ns my-gist-script)
|
||||
(defn -main [& args]
|
||||
(println "Hello from gist script!"))
|
||||
(ns user (:require [my-gist-script]))
|
||||
(apply my-gist-script/-main *command-line-args*)
|
||||
|
||||
$ bb my-script.clj
|
||||
Hello from gist script!
|
||||
```
|
||||
|
||||
## Parsing command line arguments
|
||||
|
||||
Babashka ships with `clojure.tools.cli`:
|
||||
|
|
@ -446,22 +523,27 @@ A socket REPL client for Emacs is
|
|||
|
||||
## Spawning and killing a process
|
||||
|
||||
You may use the `conch` namespace for this. It maps to
|
||||
[`me.raynes.conch.low-level`](https://github.com/clj-commons/conch#low-level-usage).
|
||||
Use the `java.lang.ProcessBuilder` class.
|
||||
|
||||
Example:
|
||||
|
||||
``` clojure
|
||||
$ bb '
|
||||
(def ws (conch/proc "python" "-m" "SimpleHTTPServer" "1777"))
|
||||
(net/wait-for-it "localhost" 1777) (conch/destroy ws)'
|
||||
user=> (def ws (-> (ProcessBuilder. ["python" "-m" "SimpleHTTPServer" "1777"]) (.start)))
|
||||
#'user/ws
|
||||
user=> (wait/wait-for-port "localhost" 1777)
|
||||
{:host "localhost", :port 1777, :took 2}
|
||||
user=> (.destroy ws)
|
||||
nil
|
||||
```
|
||||
|
||||
Also see this [example](examples/process_builder.clj).
|
||||
|
||||
## Async
|
||||
|
||||
Apart from `future` for creating threads and the `conch` namespace for creating
|
||||
processes, you may use the `async` namespace, which maps to `clojure.core.async`, for asynchronous scripting. The following
|
||||
example shows how to get first available value from two different processes:
|
||||
Apart from `future` and `pmap` for creating threads, you may use the `async`
|
||||
namespace, which maps to `clojure.core.async`, for asynchronous scripting. The
|
||||
following example shows how to get first available value from two different
|
||||
processes:
|
||||
|
||||
``` clojure
|
||||
bb '
|
||||
|
|
@ -487,9 +569,6 @@ same. Multi-threading is supported (`pmap`, `future`).
|
|||
|
||||
Differences with Clojure:
|
||||
|
||||
- No first class vars. Note that you can define and redefine global values with
|
||||
`def` / `defn`, but there is no `var` indirection.
|
||||
|
||||
- A subset of Java classes are supported.
|
||||
|
||||
- Only the `clojure.core`, `clojure.set`, `clojure.string` and `clojure.walk`
|
||||
|
|
@ -500,6 +579,62 @@ Differences with Clojure:
|
|||
|
||||
- No support for unboxed types.
|
||||
|
||||
## External resources
|
||||
|
||||
### Tools and libraries
|
||||
|
||||
The following libraries are known to work with Babashka:
|
||||
|
||||
#### [deps.clj](https://github.com/borkdude/deps.clj)
|
||||
|
||||
A port of the [clojure](https://github.com/clojure/brew-install/) bash script to
|
||||
Clojure / babashka.
|
||||
|
||||
#### [spartan.test](https://github.com/borkdude/spartan.test/)
|
||||
|
||||
A minimal test framework compatible with babashka.
|
||||
|
||||
#### [medley](https://github.com/borkdude/medley/)
|
||||
|
||||
A fork of [medley](https://github.com/weavejester/medley) made compatible with
|
||||
babashka. Requires `bb` >= v0.0.58.
|
||||
|
||||
#### [clj-http-lite](https://github.com/borkdude/clj-http-lite)
|
||||
|
||||
This fork does not depend on any other libraries. Example:
|
||||
|
||||
``` shell
|
||||
$ export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {clj-http-lite {:git/url "https://github.com/borkdude/clj-http-lite" :sha "f44ebe45446f0f44f2b73761d102af3da6d0a13e"}}}' -Spath)"
|
||||
|
||||
$ bb "(require '[clj-http.lite.client :as client]) (:status (client/get \"https://www.clojure.org\"))"
|
||||
200
|
||||
```
|
||||
|
||||
#### [limit-break](https://github.com/technomancy/limit-break)
|
||||
|
||||
A debug REPL library. Example:
|
||||
|
||||
``` shell
|
||||
$ export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {limit-break {:git/url "https://github.com/technomancy/limit-break" :sha "050fcfa0ea29fe3340927533a6fa6fffe23bfc2f" :deps/manifest :deps}}}' -Spath)"
|
||||
|
||||
$ bb "(require '[limit.break :as lb]) (let [x 1] (lb/break))"
|
||||
Babashka v0.0.49 REPL.
|
||||
Use :repl/quit or :repl/exit to quit the REPL.
|
||||
Clojure rocks, Bash reaches.
|
||||
|
||||
break> x
|
||||
1
|
||||
```
|
||||
|
||||
### Blogs
|
||||
|
||||
- [Clojure Start Time in 2019](https://stuartsierra.com/2019/12/21/clojure-start-time-in-2019) by Stuart Sierra
|
||||
- [Advent of Random
|
||||
Hacks](https://lambdaisland.com/blog/2019-12-19-advent-of-parens-19-advent-of-random-hacks)
|
||||
by Arne Brasseur
|
||||
- [Clojure in the Shell](https://lambdaisland.com/blog/2019-12-05-advent-of-parens-5-clojure-in-the-shell) by Arne Brasseur
|
||||
- [Clojure Tool](https://purelyfunctional.tv/issues/purelyfunctional-tv-newsletter-351-clojure-tool-babashka/) by Eric Normand
|
||||
|
||||
## Developing Babashka
|
||||
|
||||
To work on Babashka itself make sure Git submodules are checked out.
|
||||
|
|
@ -520,6 +655,19 @@ You need [Leiningen](https://leiningen.org/), and for building binaries you need
|
|||
|
||||
`lein repl` will get you a standard REPL/nREPL connection. To work on tests use `lein with-profiles +test repl`.
|
||||
|
||||
### Adding classes
|
||||
|
||||
Add necessary classes to `babashka/impl/classes.clj`. For every addition, write
|
||||
a unit test, so it's clear why it is added and removing it will break the
|
||||
tests. Try to reduce the size of the binary by only adding the necessary parts
|
||||
of a class in `:instance-check`, `:constructors`, `:methods`, `:fields` or
|
||||
`:custom`.
|
||||
|
||||
The `reflection.json` file that is needed for GraalVM compilation is generated
|
||||
with:
|
||||
|
||||
lein with-profiles +reflection run
|
||||
|
||||
### Test
|
||||
|
||||
Test on the JVM (for development):
|
||||
|
|
@ -553,7 +701,7 @@ welcome!
|
|||
### Delete a list of files returned by a Unix command
|
||||
|
||||
```
|
||||
find . | grep conflict | bb -i '(doseq [f *in*] (.delete (io/file f)))'
|
||||
find . | grep conflict | bb -i '(doseq [f *input*] (.delete (io/file f)))'
|
||||
```
|
||||
|
||||
### Calculate aggregate size of directory
|
||||
|
|
@ -587,7 +735,7 @@ $ cat /tmp/test.txt
|
|||
3 Babashka
|
||||
4 Goodbye
|
||||
|
||||
$ < /tmp/test.txt bb -io '(shuffle *in*)'
|
||||
$ < /tmp/test.txt bb -io '(shuffle *input*)'
|
||||
3 Babashka
|
||||
2 Clojure
|
||||
4 Goodbye
|
||||
|
|
@ -601,7 +749,7 @@ For converting JSON to EDN, see [jet](https://github.com/borkdude/jet).
|
|||
``` shellsession
|
||||
$ curl -s https://api.github.com/repos/borkdude/babashka/tags |
|
||||
jet --from json --keywordize --to edn |
|
||||
bb '(-> *in* first :name (subs 1))'
|
||||
bb '(-> *input* first :name (subs 1))'
|
||||
"0.0.4"
|
||||
```
|
||||
|
||||
|
|
@ -610,16 +758,18 @@ bb '(-> *in* first :name (subs 1))'
|
|||
``` shellsession
|
||||
$ curl -s https://api.github.com/repos/borkdude/babashka/releases |
|
||||
jet --from json --keywordize |
|
||||
bb '(-> *in* first :assets)' |
|
||||
bb '(some #(re-find #".*linux.*" (:browser_download_url %)) *in*)'
|
||||
bb '(-> *input* first :assets)' |
|
||||
bb '(some #(re-find #".*linux.*" (:browser_download_url %)) *input*)'
|
||||
"https://github.com/borkdude/babashka/releases/download/v0.0.4/babashka-0.0.4-linux-amd64.zip"
|
||||
```
|
||||
|
||||
### View download statistics from Clojars
|
||||
|
||||
Contributed by [@plexus](https://github.com/plexus).
|
||||
|
||||
``` shellsession
|
||||
$ curl https://clojars.org/stats/all.edn |
|
||||
bb -o '(for [[[group art] counts] *in*] (str (reduce + (vals counts)) " " group "/" art))' |
|
||||
bb -o '(for [[[group art] counts] *input*] (str (reduce + (vals counts)) " " group "/" art))' |
|
||||
sort -rn |
|
||||
less
|
||||
14113842 clojure-complete/clojure-complete
|
||||
|
|
@ -665,6 +815,29 @@ clj-http/clj-http can be upgraded from 3.4.0 to 3.10.0
|
|||
cheshire/cheshire can be upgraded from 5.8.1 to 5.9.0
|
||||
```
|
||||
|
||||
### Convert project.clj to deps.edn
|
||||
|
||||
Contributed by [@plexus](https://github.com/plexus).
|
||||
|
||||
``` shellsession
|
||||
$ cat project.clj |
|
||||
sed -e 's/#=//g' -e 's/~@//g' -e 's/~//g' |
|
||||
bb '(let [{:keys [dependencies source-paths resource-paths]} (apply hash-map (drop 3 *input*))]
|
||||
{:paths (into source-paths resource-paths)
|
||||
:deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))}) ' |
|
||||
jet --pretty > deps.edn
|
||||
```
|
||||
|
||||
### Print current time in California
|
||||
|
||||
See [examples/pst.clj](https://github.com/borkdude/babashka/blob/master/examples/pst.clj)
|
||||
|
||||
### Tiny http server
|
||||
|
||||
See [examples/http_server.clj](https://github.com/borkdude/babashka/blob/master/examples/http_server.clj)
|
||||
|
||||
Original by [@souenzzo](https://gist.github.com/souenzzo/a959a4c5b8c0c90df76fe33bb7dfe201)
|
||||
|
||||
## Thanks
|
||||
|
||||
- [adgoji](https://www.adgoji.com/) for financial support
|
||||
|
|
@ -677,5 +850,3 @@ Distributed under the EPL License. See LICENSE.
|
|||
|
||||
This project contains code from:
|
||||
- Clojure, which is licensed under the same EPL License.
|
||||
- [conch](https://github.com/clj-commons/conch), which is licensed under the
|
||||
same EPL License.
|
||||
|
|
|
|||
12
deps.edn
Normal file
12
deps.edn
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{:paths ["src" "sci/src" "resources" "sci/resources"],
|
||||
:deps {org.clojure/clojure {:mvn/version "1.10.1"},
|
||||
org.clojure/tools.reader {:mvn/version "1.3.2"},
|
||||
borkdude/edamame {:mvn/version "0.0.10-alpha.4"},
|
||||
borkdude/graal.locking {:mvn/version "0.0.2"},
|
||||
borkdude/sci.impl.reflector {:mvn/version "0.0.1"}
|
||||
org.clojure/core.async {:mvn/version "0.4.500"},
|
||||
org.clojure/tools.cli {:mvn/version "0.4.2"},
|
||||
org.clojure/data.csv {:mvn/version "0.1.4"},
|
||||
cheshire {:mvn/version "5.9.0"}}
|
||||
:aliases {:main
|
||||
{:main-opts ["-m" "babashka.main"]}}}
|
||||
51
examples/http_server.clj
Executable file
51
examples/http_server.clj
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env bb
|
||||
|
||||
(import (java.net ServerSocket))
|
||||
(require '[clojure.string :as string]
|
||||
'[clojure.java.io :as io])
|
||||
|
||||
(with-open [server-socket (new ServerSocket 8080)
|
||||
client-socket (.accept server-socket)]
|
||||
(loop []
|
||||
(let [out (io/writer (.getOutputStream client-socket))
|
||||
in (io/reader (.getInputStream client-socket))
|
||||
[req-line & headers] (loop [headers []]
|
||||
(let [line (.readLine in)]
|
||||
(if (string/blank? line)
|
||||
headers
|
||||
(recur (conj headers line)))))
|
||||
[_ _ path _] (re-find #"([^\s]+)\s([^\s]+)\s([^\s]+)" req-line)
|
||||
f (io/file (format "./%s" path))
|
||||
status (if (.exists f)
|
||||
200
|
||||
404)
|
||||
html (fn html-fn [tag & body]
|
||||
(let [attrs? (map? (first body))
|
||||
attrs-str (str (when attrs?
|
||||
(format " %s" (string/join " " (for [[k v] (first body)]
|
||||
(format "%s=%s" (name k) (name v)))))))]
|
||||
(format "<%s%s>%s</%s>"
|
||||
(name tag)
|
||||
attrs-str
|
||||
(string/join (if attrs? (rest body) body))
|
||||
(name tag))))
|
||||
body (cond
|
||||
(not (.exists f)) ""
|
||||
(.isFile f) (slurp f)
|
||||
(.isDirectory f) (format "<!DOCTYPE html>\n%s"
|
||||
(html :html
|
||||
(html :head
|
||||
(html :title path))
|
||||
(html :body
|
||||
(html :h1 path)
|
||||
(html :tt
|
||||
(apply html :pre
|
||||
(for [i (.list f)]
|
||||
(html :div (html :a {:href (format "\"%s\"" i)} i)))))))))]
|
||||
(prn path)
|
||||
(.write out (format "HTTP/1.1 %s OK\r\nContent-Length: %s\r\n\r\n%s"
|
||||
status
|
||||
(count body)
|
||||
body))
|
||||
(.flush out))
|
||||
(recur)))
|
||||
19
examples/process_builder.clj
Executable file
19
examples/process_builder.clj
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env bb
|
||||
|
||||
(require '[clojure.java.io :as io])
|
||||
(import '[java.lang ProcessBuilder$Redirect])
|
||||
|
||||
(defn grep [input pattern]
|
||||
(let [proc (-> (ProcessBuilder. ["grep" pattern])
|
||||
(.redirectOutput ProcessBuilder$Redirect/INHERIT)
|
||||
(.redirectError ProcessBuilder$Redirect/INHERIT)
|
||||
(.start))
|
||||
proc-input (.getOutputStream proc)]
|
||||
(with-open [w (io/writer proc-input)]
|
||||
(binding [*out* w]
|
||||
(print input)
|
||||
(flush)))
|
||||
(.waitFor proc)
|
||||
nil))
|
||||
|
||||
(grep "hello\nbye\n" "bye")
|
||||
7
examples/pst.clj
Executable file
7
examples/pst.clj
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bb
|
||||
|
||||
(def now (java.time.ZonedDateTime/now))
|
||||
(def LA-timezone (java.time.ZoneId/of "America/Los_Angeles"))
|
||||
(def LA-time (.withZoneSameInstant now LA-timezone))
|
||||
(def pattern (java.time.format.DateTimeFormatter/ofPattern "HH:mm"))
|
||||
(println (.format LA-time pattern))
|
||||
BIN
logo/babashka.png
Normal file
BIN
logo/babashka.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
30
logo/babashka.svg
Normal file
30
logo/babashka.svg
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<svg width="882" height="648" viewBox="0 0 2944 2162" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1742.91 1219.89C1857.93 1138.38 1933 1004.21 1933 852.5C1933 603.972 1761 280.5 1483 139C1207.5 288 1033 603.972 1033 852.5C1033 1004.21 1108.07 1138.38 1223.09 1219.89C1218.98 1220.44 1214.95 1221.14 1211 1222C1123.61 1241.07 1017 1385.05 1017 1385.05H1281C1327.97 1385.05 1372.63 1367.41 1407.96 1347.62C1425.12 1370.32 1452.34 1385 1483 1385C1513.66 1385 1540.89 1370.32 1558.04 1347.62C1593.37 1367.41 1638.03 1385.05 1685 1385.05H1949C1949 1385.05 1842.39 1241.07 1755 1222C1751.05 1221.14 1747.02 1220.44 1742.91 1219.89Z" fill="url(#paint0_linear)"/>
|
||||
<circle cx="1482.5" cy="878.5" r="311.5" fill="white"/>
|
||||
<path d="M1212 745.5C1396.5 758.5 1505.5 713.5 1581 602C1581 602 1435.5 553 1347 602C1258.8 650.834 1212 745.5 1212 745.5Z" fill="#B4B4B4"/>
|
||||
<path d="M1728 718C1654 710 1588 686 1556.5 595.5C1556.5 595.5 1621.93 610.435 1688 670.614C1756.62 733.114 1728 718 1728 718Z" fill="#B4B4B4"/>
|
||||
<circle cx="1482.5" cy="878.5" r="311.5" stroke="#0A0000" stroke-width="40"/>
|
||||
<path d="M1544 745H1421L1451 775V865C1455.5 835.5 1511.5 834.5 1514.5 865L1522 775L1544 745Z" fill="black"/>
|
||||
<path d="M1098.12 785C1098.12 762.909 1116.03 745 1138.12 745H1423.02C1447.2 745 1465.85 766.292 1462.67 790.264L1437.91 976.764C1435.27 996.646 1418.31 1011.5 1398.26 1011.5H1138.12C1116.03 1011.5 1098.12 993.591 1098.12 971.5V785Z" fill="black"/>
|
||||
<path d="M1216.1 967.55V951.05H1210.55C1206.95 951.05 1204.55 948.5 1203.35 944.75L1180.55 876.05C1179.05 871.7 1177.25 868.55 1174.85 866.15C1170.35 861.5 1164.5 860 1157.9 860H1150.7V877.25H1155.5C1159.55 877.25 1162.7 878.75 1164.05 883.55L1167.2 894.65L1139 967.55H1159.55L1176.5 919.55L1185.5 948.5C1188.95 959.75 1194.8 967.55 1208 967.55H1216.1Z" fill="white"/>
|
||||
<path d="M1248.8 951.05V967.55H1304.8V951.05H1248.8Z" fill="white"/>
|
||||
<path d="M1503.01 790.267C1499.83 766.294 1518.48 745 1542.66 745H1827C1849.09 745 1867 762.909 1867 785V971.096C1867 993.187 1849.09 1011.1 1827 1011.1H1567.38C1547.33 1011.1 1530.37 996.244 1527.73 976.362L1503.01 790.267Z" fill="black"/>
|
||||
<path d="M1649.3 968V951.5H1643.75C1640.15 951.5 1637.75 948.95 1636.55 945.2L1613.75 876.5C1612.25 872.15 1610.45 869 1608.05 866.6C1603.55 861.95 1597.7 860.45 1591.1 860.45H1583.9V877.7H1588.7C1592.75 877.7 1595.9 879.2 1597.25 884L1600.4 895.1L1572.2 968H1592.75L1609.7 920L1618.7 948.95C1622.15 960.2 1628 968 1641.2 968H1649.3Z" fill="white"/>
|
||||
<path d="M1682 951.5V968H1738V951.5H1682Z" fill="white"/>
|
||||
<path d="M245.923 1711.64C254.47 1700.19 264.812 1691.21 276.949 1684.72C289.085 1678.05 301.991 1674.72 315.667 1674.72C349.684 1674.72 374.897 1687.37 391.308 1712.67C407.889 1737.79 416.18 1773.26 416.18 1819.08C416.18 1847.45 411.906 1872.67 403.359 1894.72C394.983 1916.6 382.59 1933.78 366.18 1946.26C349.94 1958.56 330.282 1964.72 307.205 1964.72C293.53 1964.72 280.795 1961.81 269 1956C257.376 1950.36 247.633 1942.15 239.769 1931.38L236.692 1956H164.897V1575.49L245.923 1567.03V1711.64ZM285.923 1905.74C317.034 1905.74 332.59 1877.2 332.59 1820.1C332.59 1798.22 330.88 1781.04 327.462 1768.56C324.043 1755.91 319.171 1747.11 312.846 1742.15C306.692 1737.03 299.085 1734.46 290.026 1734.46C273.274 1734.46 258.573 1744.97 245.923 1766V1880.87C251.222 1889.25 257.034 1895.49 263.359 1899.59C269.855 1903.69 277.376 1905.74 285.923 1905.74Z" fill="black"/>
|
||||
<path d="M701.745 1877.54C701.745 1887.62 703.113 1895.06 705.848 1899.85C708.583 1904.46 713.198 1907.97 719.694 1910.36L703.027 1963.69C686.446 1962.15 672.686 1958.56 661.745 1952.92C650.976 1947.11 642.515 1938.74 636.361 1927.79C626.275 1939.93 613.198 1949.16 597.13 1955.49C581.233 1961.64 564.395 1964.72 546.617 1964.72C528.156 1964.72 511.916 1961.13 497.899 1953.95C484.053 1946.6 473.369 1936.51 465.848 1923.69C458.327 1910.7 454.566 1895.83 454.566 1879.08C454.566 1859.59 459.78 1842.92 470.207 1829.08C480.634 1815.23 495.763 1804.72 515.592 1797.54C535.421 1790.19 559.267 1786.51 587.13 1786.51H623.797V1776.26C623.797 1748.39 605.848 1734.46 569.951 1734.46C560.891 1734.46 549.438 1735.74 535.592 1738.31C521.916 1740.87 508.498 1744.38 495.335 1748.82L476.617 1694.97C493.711 1688.48 511.745 1683.52 530.72 1680.1C549.694 1676.51 567.045 1674.72 582.771 1674.72C622.771 1674.72 652.6 1682.84 672.258 1699.08C691.916 1715.32 701.745 1739.25 701.745 1770.87V1877.54ZM574.566 1906.77C583.797 1906.77 593.113 1904.12 602.515 1898.82C611.916 1893.35 619.01 1886 623.797 1876.77V1832.67H603.797C581.574 1832.67 565.079 1836.09 554.31 1842.92C543.54 1849.76 538.156 1859.93 538.156 1873.44C538.156 1884.03 541.318 1892.24 547.643 1898.05C554.139 1903.86 563.113 1906.77 574.566 1906.77Z" fill="black"/>
|
||||
<path d="M984.204 1711.64C992.751 1700.19 1003.09 1691.21 1015.23 1684.72C1027.37 1678.05 1040.27 1674.72 1053.95 1674.72C1087.97 1674.72 1113.18 1687.37 1129.59 1712.67C1146.17 1737.79 1154.46 1773.26 1154.46 1819.08C1154.46 1847.45 1150.19 1872.67 1141.64 1894.72C1133.26 1916.6 1120.87 1933.78 1104.46 1946.26C1088.22 1958.56 1068.56 1964.72 1045.49 1964.72C1031.81 1964.72 1019.08 1961.81 1007.28 1956C995.657 1950.36 985.914 1942.15 978.05 1931.38L974.974 1956H903.179V1575.49L984.204 1567.03V1711.64ZM1024.2 1905.74C1055.32 1905.74 1070.87 1877.2 1070.87 1820.1C1070.87 1798.22 1069.16 1781.04 1065.74 1768.56C1062.32 1755.91 1057.45 1747.11 1051.13 1742.15C1044.97 1737.03 1037.37 1734.46 1028.31 1734.46C1011.55 1734.46 996.854 1744.97 984.204 1766V1880.87C989.503 1889.25 995.315 1895.49 1001.64 1899.59C1008.14 1903.69 1015.66 1905.74 1024.2 1905.74Z" fill="black"/>
|
||||
<path d="M1440.03 1877.54C1440.03 1887.62 1441.39 1895.06 1444.13 1899.85C1446.86 1904.46 1451.48 1907.97 1457.98 1910.36L1441.31 1963.69C1424.73 1962.15 1410.97 1958.56 1400.03 1952.92C1389.26 1947.11 1380.8 1938.74 1374.64 1927.79C1364.56 1939.93 1351.48 1949.16 1335.41 1955.49C1319.51 1961.64 1302.68 1964.72 1284.9 1964.72C1266.44 1964.72 1250.2 1961.13 1236.18 1953.95C1222.33 1946.6 1211.65 1936.51 1204.13 1923.69C1196.61 1910.7 1192.85 1895.83 1192.85 1879.08C1192.85 1859.59 1198.06 1842.92 1208.49 1829.08C1218.92 1815.23 1234.04 1804.72 1253.87 1797.54C1273.7 1790.19 1297.55 1786.51 1325.41 1786.51H1362.08V1776.26C1362.08 1748.39 1344.13 1734.46 1308.23 1734.46C1299.17 1734.46 1287.72 1735.74 1273.87 1738.31C1260.2 1740.87 1246.78 1744.38 1233.62 1748.82L1214.9 1694.97C1231.99 1688.48 1250.03 1683.52 1269 1680.1C1287.98 1676.51 1305.33 1674.72 1321.05 1674.72C1361.05 1674.72 1390.88 1682.84 1410.54 1699.08C1430.2 1715.32 1440.03 1739.25 1440.03 1770.87V1877.54ZM1312.85 1906.77C1322.08 1906.77 1331.39 1904.12 1340.8 1898.82C1350.2 1893.35 1357.29 1886 1362.08 1876.77V1832.67H1342.08C1319.86 1832.67 1303.36 1836.09 1292.59 1842.92C1281.82 1849.76 1276.44 1859.93 1276.44 1873.44C1276.44 1884.03 1279.6 1892.24 1285.92 1898.05C1292.42 1903.86 1301.39 1906.77 1312.85 1906.77Z" fill="black"/>
|
||||
<path d="M1627.64 1906.77C1641.49 1906.77 1652.43 1904.63 1660.46 1900.36C1668.67 1895.91 1672.77 1889.5 1672.77 1881.13C1672.77 1875.15 1671.15 1870.27 1667.9 1866.51C1664.65 1862.58 1658.58 1858.91 1649.7 1855.49C1640.81 1851.9 1626.96 1847.54 1608.16 1842.41C1580.81 1835.06 1559.87 1824.97 1545.34 1812.15C1530.98 1799.33 1523.8 1781.56 1523.8 1758.82C1523.8 1742.41 1528.33 1727.88 1537.39 1715.23C1546.62 1702.58 1560.12 1692.67 1577.9 1685.49C1595.68 1678.31 1617.05 1674.72 1642 1674.72C1685.25 1674.72 1722 1685.74 1752.26 1707.79L1719.95 1755.49C1708.16 1748.31 1695.76 1742.67 1682.77 1738.56C1669.95 1734.46 1657.13 1732.41 1644.31 1732.41C1631.15 1732.41 1621.32 1734.21 1614.82 1737.79C1608.5 1741.21 1605.34 1746.43 1605.34 1753.44C1605.34 1758.22 1606.96 1762.24 1610.21 1765.49C1613.63 1768.74 1619.7 1772.07 1628.41 1775.49C1637.3 1778.91 1651.06 1783.26 1669.7 1788.56C1689.35 1794.03 1705.34 1800.1 1717.64 1806.77C1729.95 1813.26 1739.52 1821.98 1746.36 1832.92C1753.37 1843.69 1756.87 1857.62 1756.87 1874.72C1756.87 1893.86 1751.06 1910.27 1739.44 1923.95C1727.99 1937.45 1712.52 1947.62 1693.03 1954.46C1673.54 1961.3 1651.92 1964.72 1628.16 1964.72C1602.69 1964.72 1579.78 1961.13 1559.44 1953.95C1539.1 1946.6 1521.58 1936.51 1506.87 1923.69L1547.64 1878.05C1558.93 1886.94 1571.32 1893.95 1584.82 1899.08C1598.33 1904.21 1612.6 1906.77 1627.64 1906.77Z" fill="black"/>
|
||||
<path d="M1907.06 1710.62C1929.79 1686.68 1956.46 1674.72 1987.06 1674.72C2011.16 1674.72 2029.62 1681.81 2042.44 1696C2055.43 1710.02 2061.93 1730.02 2061.93 1756V1956H1980.9V1778.56C1980.9 1767.45 1980.05 1758.74 1978.34 1752.41C1976.8 1746.09 1974.15 1741.56 1970.39 1738.82C1966.63 1735.91 1961.41 1734.46 1954.75 1734.46C1946.54 1734.46 1938.59 1737.28 1930.9 1742.92C1923.21 1748.56 1915.26 1756.77 1907.06 1767.54V1956H1826.03V1575.49L1907.06 1567.54V1710.62Z" fill="black"/>
|
||||
<path d="M2337.72 1956H2256.69V1575.49L2337.72 1567.03V1956ZM2425.67 1804.21L2522.59 1956H2430.28L2340.8 1806.77L2430.28 1683.69H2515.16L2425.67 1804.21Z" fill="black"/>
|
||||
<path d="M2793.54 1877.54C2793.54 1887.62 2794.91 1895.06 2797.64 1899.85C2800.38 1904.46 2805 1907.97 2811.49 1910.36L2794.82 1963.69C2778.24 1962.15 2764.48 1958.56 2753.54 1952.92C2742.77 1947.11 2734.31 1938.74 2728.16 1927.79C2718.07 1939.93 2705 1949.16 2688.93 1955.49C2673.03 1961.64 2656.19 1964.72 2638.41 1964.72C2619.95 1964.72 2603.71 1961.13 2589.7 1953.95C2575.85 1946.6 2565.17 1936.51 2557.64 1923.69C2550.12 1910.7 2546.36 1895.83 2546.36 1879.08C2546.36 1859.59 2551.58 1842.92 2562 1829.08C2572.43 1815.23 2587.56 1804.72 2607.39 1797.54C2627.22 1790.19 2651.06 1786.51 2678.93 1786.51H2715.59V1776.26C2715.59 1748.39 2697.64 1734.46 2661.75 1734.46C2652.69 1734.46 2641.23 1735.74 2627.39 1738.31C2613.71 1740.87 2600.29 1744.38 2587.13 1748.82L2568.41 1694.97C2585.51 1688.48 2603.54 1683.52 2622.52 1680.1C2641.49 1676.51 2658.84 1674.72 2674.57 1674.72C2714.57 1674.72 2744.4 1682.84 2764.06 1699.08C2783.71 1715.32 2793.54 1739.25 2793.54 1770.87V1877.54ZM2666.36 1906.77C2675.59 1906.77 2684.91 1904.12 2694.31 1898.82C2703.71 1893.35 2710.81 1886 2715.59 1876.77V1832.67H2695.59C2673.37 1832.67 2656.88 1836.09 2646.11 1842.92C2635.34 1849.76 2629.95 1859.93 2629.95 1873.44C2629.95 1884.03 2633.11 1892.24 2639.44 1898.05C2645.94 1903.86 2654.91 1906.77 2666.36 1906.77Z" fill="black"/>
|
||||
<path d="M862 1819C862 1848.27 838.271 1872 809 1872C779.729 1872 756 1848.27 756 1819C756 1789.73 779.729 1766 809 1766C838.271 1766 862 1789.73 862 1819Z" fill="black"/>
|
||||
<path d="M2215.5 1819C2215.5 1848.27 2191.77 1872 2162.5 1872C2133.23 1872 2109.5 1848.27 2109.5 1819C2109.5 1789.73 2133.23 1766 2162.5 1766C2191.77 1766 2215.5 1789.73 2215.5 1819Z" fill="black"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="1499" y1="139" x2="1499" y2="1385.52" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E41F26"/>
|
||||
<stop offset="1" stop-color="#B70000"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
BIN
logo/icon.png
Normal file
BIN
logo/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
18
logo/icon.svg
Normal file
18
logo/icon.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<svg width="128" height="128" viewBox="0 0 1472 1472" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M995.911 1193.89C1110.93 1112.38 1186 978.206 1186 826.5C1186 577.972 1014 254.5 736 113C460.5 262 286 577.972 286 826.5C286 978.206 361.07 1112.38 476.089 1193.89C471.983 1194.44 467.949 1195.14 464 1196C376.611 1215.07 270 1359.05 270 1359.05H534C580.972 1359.05 625.631 1341.41 660.956 1321.62C678.115 1344.32 705.344 1359 736 1359C766.656 1359 793.885 1344.32 811.044 1321.62C846.369 1341.41 891.028 1359.05 938 1359.05H1202C1202 1359.05 1095.39 1215.07 1008 1196C1004.05 1195.14 1000.02 1194.44 995.911 1193.89Z" fill="url(#paint0_linear)"/>
|
||||
<circle cx="735.5" cy="852.5" r="311.5" fill="white"/>
|
||||
<path d="M443 750.417C662 765.866 791.382 712.388 881 579.881C881 579.881 708.293 521.649 603.244 579.881C498.55 637.916 443 750.417 443 750.417Z" fill="#B4B4B4"/>
|
||||
<path d="M1039.99 748.282C914.862 734.745 803.264 694.135 750 541C750 541 860.633 566.272 972.355 668.101C1088.39 773.857 1039.99 748.282 1039.99 748.282Z" fill="#B4B4B4"/>
|
||||
<circle cx="735.5" cy="852.5" r="311.5" stroke="#0A0000" stroke-width="40"/>
|
||||
<path d="M797 719H674L704 749V839C708.5 809.5 764.5 808.5 767.5 839L775 749L797 719Z" fill="black"/>
|
||||
<path d="M351.117 759C351.117 736.909 369.026 719 391.117 719H676.018C700.2 719 718.852 740.292 715.67 764.264L690.91 950.764C688.27 970.646 671.314 985.5 651.258 985.5H391.117C369.026 985.5 351.117 967.591 351.117 945.5V759Z" fill="black"/>
|
||||
<path d="M756.012 764.267C752.828 740.294 771.481 719 795.664 719H1080C1102.09 719 1120 736.909 1120 759V945.096C1120 967.187 1102.09 985.096 1080 985.096H820.381C800.325 985.096 783.37 970.244 780.729 950.362L756.012 764.267Z" fill="black"/>
|
||||
<path d="M1024 952V921.47H1013.71C1007.03 921.47 1002.58 916.752 1000.35 909.813L958.064 782.697C955.282 774.649 951.944 768.82 947.492 764.379C939.146 755.775 928.296 753 916.054 753H902.7V784.918H911.603C919.115 784.918 924.957 787.693 927.461 796.575L933.303 817.113L881 952H919.115L950.553 863.185L967.245 916.752C973.644 937.568 984.494 952 1008.98 952H1024Z" fill="white"/>
|
||||
<path d="M590 952V921.47H579.706C573.029 921.47 568.578 916.752 566.352 909.813L524.064 782.697C521.282 774.649 517.944 768.82 513.492 764.379C505.146 755.775 494.296 753 482.054 753H468.7V784.918H477.603C485.115 784.918 490.957 787.693 493.461 796.575L499.303 817.113L447 952H485.115L516.553 863.185L533.245 916.752C539.644 937.568 550.494 952 574.977 952H590Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="752" y1="113" x2="752" y2="1359.52" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E41F26"/>
|
||||
<stop offset="1" stop-color="#B70000"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -11,7 +11,9 @@
|
|||
:resource-paths ["resources" "sci/resources"]
|
||||
:dependencies [[org.clojure/clojure "1.10.1"]
|
||||
[org.clojure/tools.reader "1.3.2"]
|
||||
[borkdude/edamame "0.0.10-alpha.2"]
|
||||
[borkdude/edamame "0.0.10-alpha.4"]
|
||||
[borkdude/graal.locking "0.0.2"]
|
||||
[borkdude/sci.impl.reflector "0.0.1"]
|
||||
[org.clojure/core.async "0.4.500"]
|
||||
[org.clojure/tools.cli "0.4.2"]
|
||||
[org.clojure/data.csv "0.1.4"]
|
||||
|
|
@ -22,7 +24,8 @@
|
|||
:jvm-opts ["-Dclojure.compiler.direct-linking=true"
|
||||
"-Dclojure.spec.skip-macros=true"]
|
||||
:main babashka.main
|
||||
:aot :all}}
|
||||
:aot :all}
|
||||
:reflection {:main babashka.impl.classes/generate-reflection-file}}
|
||||
:aliases {"bb" ["run" "-m" "babashka.main"]}
|
||||
:deploy-repositories [["clojars" {:url "https://clojars.org/repo"
|
||||
:username :env/clojars_user
|
||||
|
|
|
|||
189
reflection.json
189
reflection.json
|
|
@ -1,189 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name":"java.lang.ArithmeticException",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.AssertionError",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Boolean",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.BufferedWriter",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.BufferedReader",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name": "java.lang.Class",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Double",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Exception",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name": "clojure.lang.ExceptionInfo",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Integer",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.File",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"clojure.lang.LineNumberingPushbackReader",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.LinkedBlockingQueue",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.util.regex.Pattern",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Process",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.ProcessBuilder",
|
||||
"allPublicConstructors":true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.String",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.StringReader",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.StringWriter",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.System",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Thread",
|
||||
"methods": [{"name":"run"},{"name":"toString"},{"name":"isInterrupted"},{"name":"currentThread"},{"name":"getName"},{"name":"join"},{"name":"getThreadGroup"},{"name":"getStackTrace"},{"name":"holdsLock"},{"name":"checkAccess"},{"name":"dumpStack"},{"name":"yield"},{"name":"setPriority"},{"name":"setDaemon"},{"name":"start"},{"name":"sleep"},{"name":"interrupt"},{"name":"interrupted"},{"name":"isAlive"},{"name":"getPriority"},{"name":"setName"},{"name":"activeCount"},{"name":"enumerate"},{"name":"isDaemon"},{"name":"getContextClassLoader"},{"name":"setContextClassLoader"},{"name":"getAllStackTraces"},{"name":"getId"},{"name":"getState"},{"name":"setDefaultUncaughtExceptionHandler"},{"name":"getDefaultUncaughtExceptionHandler"},{"name":"getUncaughtExceptionHandler"},{"name":"setUncaughtExceptionHandler"}],
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.UNIXProcess",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.attribute.FileAttribute",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.attribute.PosixFilePermission",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.attribute.PosixFilePermissions",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Path",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.CopyOption",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.FileAlreadyExistsException",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Files",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.NoSuchFileException",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.StandardCopyOption",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"sun.nio.fs.UnixPath",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{"name":"com.sun.xml.internal.stream.XMLInputFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]},
|
||||
{"name":"com.sun.xml.internal.stream.XMLOutputFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]}
|
||||
]
|
||||
|
|
@ -1 +1 @@
|
|||
0.0.42
|
||||
0.0.60
|
||||
|
|
@ -1 +1 @@
|
|||
0.0.43-SNAPSHOT
|
||||
0.0.61-SNAPSHOT
|
||||
2
sci
2
sci
|
|
@ -1 +1 @@
|
|||
Subproject commit 07d28ee572e90a629e01b10aa5b98cb33ccdc1e5
|
||||
Subproject commit 57b584ba0a6a1f74a887d350463a700976dd37d8
|
||||
60
script/bump_version.clj
Executable file
60
script/bump_version.clj
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env bb
|
||||
|
||||
(ns bump-version
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(import '[java.lang ProcessBuilder$Redirect])
|
||||
|
||||
(defn shell-command
|
||||
"Executes shell command. Exits script when the shell-command has a non-zero exit code, propagating it.
|
||||
Accepts the following options:
|
||||
`:input`: instead of reading from stdin, read from this string.
|
||||
`:to-string?`: instead of writing to stdoud, write to a string and
|
||||
return it."
|
||||
([args] (shell-command args nil))
|
||||
([args {:keys [:input :to-string?]}]
|
||||
(let [args (mapv str args)
|
||||
pb (cond-> (-> (ProcessBuilder. ^java.util.List args)
|
||||
(.redirectError ProcessBuilder$Redirect/INHERIT))
|
||||
(not to-string?) (.redirectOutput ProcessBuilder$Redirect/INHERIT)
|
||||
(not input) (.redirectInput ProcessBuilder$Redirect/INHERIT))
|
||||
proc (.start pb)]
|
||||
(when input
|
||||
(with-open [w (io/writer (.getOutputStream proc))]
|
||||
(binding [*out* w]
|
||||
(print input)
|
||||
(flush))))
|
||||
(let [string-out
|
||||
(when to-string?
|
||||
(let [sw (java.io.StringWriter.)]
|
||||
(with-open [w (io/reader (.getInputStream proc))]
|
||||
(io/copy w sw))
|
||||
(str sw)))
|
||||
exit-code (.waitFor proc)]
|
||||
(when-not (zero? exit-code)
|
||||
(System/exit exit-code))
|
||||
string-out))))
|
||||
|
||||
(def version-file (io/file "resources" "BABASHKA_VERSION"))
|
||||
(def released-version-file (io/file "resources" "BABASHKA_RELEASED_VERSION"))
|
||||
|
||||
(case (first *command-line-args*)
|
||||
"release" (let [version-string (str/trim (slurp version-file))
|
||||
[major minor patch] (str/split version-string #"\.")
|
||||
patch (str/replace patch "-SNAPSHOT" "")
|
||||
new-version (str/join "." [major minor patch])]
|
||||
(spit version-file new-version)
|
||||
(shell-command ["git" "commit" "-a" "-m" (str "v" new-version)])
|
||||
(shell-command ["git" "diff" "HEAD^" "HEAD"]))
|
||||
"post-release" (do
|
||||
(io/copy version-file released-version-file)
|
||||
(let [version-string (str/trim (slurp version-file))
|
||||
[major minor patch] (str/split version-string #"\.")
|
||||
patch (Integer. patch)
|
||||
patch (str (inc patch) "-SNAPSHOT")
|
||||
new-version (str/join "." [major minor patch])]
|
||||
(spit version-file new-version)
|
||||
(shell-command ["git" "commit" "-a" "-m" "Version bump"])
|
||||
(shell-command ["git" "diff" "HEAD^" "HEAD"])))
|
||||
(println "Expected: release | post-release."))
|
||||
|
|
@ -23,7 +23,9 @@ BABASHKA_VERSION=$(cat resources/BABASHKA_VERSION)
|
|||
# mkdir -p src/sci
|
||||
# cp -R /tmp/sci/src/* src
|
||||
|
||||
lein with-profiles +reflection do run
|
||||
lein do clean, uberjar
|
||||
|
||||
$NATIVE_IMAGE \
|
||||
-jar target/babashka-$BABASHKA_VERSION-standalone.jar \
|
||||
-H:Name=bb \
|
||||
|
|
|
|||
17
script/lib_tests/clj_http_lite_test
Executable file
17
script/lib_tests/clj_http_lite_test
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {clj-http-lite {:git/url "https://github.com/borkdude/clj-http-lite" :sha "f44ebe45446f0f44f2b73761d102af3da6d0a13e"}}}' -Spath)
|
||||
|
||||
./bb -e "
|
||||
(require '[clj-http.lite.client :as client])
|
||||
|
||||
(prn (:status (client/get \"https://www.clojure.org\")))
|
||||
|
||||
(prn (:status (client/get \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\")))
|
||||
|
||||
(prn (:status (client/post \"https://postman-echo.com/post\")))
|
||||
|
||||
(prn (:status (client/put \"https://postman-echo.com/put\")))
|
||||
"
|
||||
9
script/lib_tests/deps_clj_test
Executable file
9
script/lib_tests/deps_clj_test
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
curl -sL https://raw.githubusercontent.com/borkdude/deps.clj/master/deps.clj -o deps_test.clj
|
||||
chmod +x deps_test.clj
|
||||
./bb deps_test.clj -Sdescribe
|
||||
rm deps_test.clj
|
||||
|
||||
11
script/lib_tests/spartan_spec_test
Executable file
11
script/lib_tests/spartan_spec_test
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
export BABASHKA_CLASSPATH=$(clojure -Sdeps '{:deps {spartan.spec {:git/url "https://github.com/borkdude/spartan.spec" :sha "16f7eec4b6589c77c96c9fcf989f78fffcee7c4c"}}}' -Spath)
|
||||
|
||||
./bb -e "
|
||||
(require '[spartan.spec :as s])
|
||||
(s/explain (s/cat :i int? :s string?) [1 :foo])
|
||||
(s/conform (s/cat :i int? :s string?) [1 \"foo\"])
|
||||
"
|
||||
7
script/run_lib_tests
Executable file
7
script/run_lib_tests
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
script/lib_tests/clj_http_lite_test
|
||||
script/lib_tests/deps_clj_test
|
||||
script/lib_tests/spartan_spec_test
|
||||
219
src-bash/bbk
219
src-bash/bbk
|
|
@ -1,219 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
function join { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
|
||||
|
||||
# Extract opts
|
||||
print_classpath=false
|
||||
describe=false
|
||||
verbose=false
|
||||
force=false
|
||||
repro=false
|
||||
tree=false
|
||||
pom=false
|
||||
resolve_tags=false
|
||||
help=false
|
||||
resolve_aliases=()
|
||||
classpath_aliases=()
|
||||
main_aliases=()
|
||||
all_aliases=()
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
case "$1" in
|
||||
-J*)
|
||||
shift
|
||||
;;
|
||||
-R*)
|
||||
resolve_aliases+=("${1:2}")
|
||||
shift
|
||||
;;
|
||||
-C*)
|
||||
classpath_aliases+=("${1:2}")
|
||||
shift
|
||||
;;
|
||||
-O*)
|
||||
shift
|
||||
;;
|
||||
-M*)
|
||||
main_aliases+=("${1:2}")
|
||||
shift
|
||||
;;
|
||||
-A*)
|
||||
all_aliases+=("${1:2}")
|
||||
shift
|
||||
;;
|
||||
-Sdeps)
|
||||
shift
|
||||
deps_data="${1}"
|
||||
shift
|
||||
;;
|
||||
-Scp)
|
||||
shift
|
||||
force_cp="${1}"
|
||||
shift
|
||||
;;
|
||||
-Spath)
|
||||
print_classpath=true
|
||||
shift
|
||||
;;
|
||||
-Sverbose)
|
||||
verbose=true
|
||||
shift
|
||||
;;
|
||||
-Sdescribe)
|
||||
describe=true
|
||||
shift
|
||||
;;
|
||||
-Sforce)
|
||||
force=true
|
||||
shift
|
||||
;;
|
||||
-Srepro)
|
||||
repro=true
|
||||
shift
|
||||
;;
|
||||
-Stree)
|
||||
tree=true
|
||||
shift
|
||||
;;
|
||||
-Spom)
|
||||
pom=true
|
||||
shift
|
||||
;;
|
||||
-Sresolve-tags)
|
||||
resolve_tags=true
|
||||
shift
|
||||
;;
|
||||
-S*)
|
||||
echo "Invalid option: $1"
|
||||
exit 1
|
||||
;;
|
||||
-h|--help|"-?")
|
||||
if [[ ${#main_aliases[@]} -gt 0 ]] || [[ ${#all_aliases[@]} -gt 0 ]]; then
|
||||
break
|
||||
else
|
||||
help=true
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Find clojure executable
|
||||
set +e
|
||||
CLOJURE_CMD=$(type -p clojure)
|
||||
set -e
|
||||
if [[ ! -n "$CLOJURE_CMD" ]]; then
|
||||
>&2 echo "Couldn't find 'clojure'."
|
||||
>&2 echo "You can launch Babashka directly using 'bb'."
|
||||
>&2 echo "To use 'bbk', please ensure 'clojure' is installed and on"
|
||||
>&2 echo "your path. See https://clojure.org/guides/getting_started"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if "$help"; then
|
||||
cat <<-END
|
||||
Usage: bbk [dep-opt*] [bb-opt*] [arg*]
|
||||
|
||||
The bbk script is a runner for Babashka which ultimately constructs and
|
||||
invokes a command-line of the form:
|
||||
|
||||
bb --classpath classpath [bb-opt*] [*args]
|
||||
|
||||
The dep-opts are used to build the classpath using the clojure tool:
|
||||
-Ralias... Concatenated resolve-deps aliases, ex: -R:bench:1.9
|
||||
-Calias... Concatenated make-classpath aliases, ex: -C:dev
|
||||
-Malias... Concatenated main option aliases, ex: -M:test
|
||||
-Aalias... Concatenated aliases of any kind, ex: -A:dev:mem
|
||||
-Sdeps EDN Deps data to use as the final deps file
|
||||
-Spath Compute classpath and echo to stdout only
|
||||
-Scp CP Do NOT compute or cache classpath, use this one instead
|
||||
-Srepro Ignore the ~/.clojure/deps.edn config file
|
||||
-Sforce Force recomputation of the classpath (don't use the cache)
|
||||
-Spom Generate (or update existing) pom.xml with deps and paths
|
||||
-Stree Print dependency tree
|
||||
-Sresolve-tags Resolve git coordinate tags to shas and update deps.edn
|
||||
-Sverbose Print important path info to console
|
||||
-Sdescribe Print environment and command parsing info as data
|
||||
|
||||
Additionally, for compatibility with clojure, -Jopt and -Oalias... dep-opts
|
||||
are accepted but ignored.
|
||||
|
||||
Babashka options:
|
||||
END
|
||||
bb -h | tail -n +9
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Execute resolve-tags command
|
||||
if "$resolve_tags"; then
|
||||
"$CLOJURE_CMD" -Sresolve-tags
|
||||
exit
|
||||
fi
|
||||
|
||||
clojure_args=()
|
||||
if [[ -n "$deps_data" ]]; then
|
||||
clojure_args+=("-Sdeps" "$deps_data")
|
||||
fi
|
||||
if [[ ${#resolve_aliases[@]} -gt 0 ]]; then
|
||||
clojure_args+=("-R$(join '' ${resolve_aliases[@]})")
|
||||
fi
|
||||
if [[ ${#classpath_aliases[@]} -gt 0 ]]; then
|
||||
clojure_args+=("-C$(join '' ${classpath_aliases[@]})")
|
||||
fi
|
||||
if [[ ${#main_aliases[@]} -gt 0 ]]; then
|
||||
clojure_args+=("-M$(join '' ${main_aliases[@]})")
|
||||
fi
|
||||
if [[ ${#all_aliases[@]} -gt 0 ]]; then
|
||||
clojure_args+=("-A$(join '' ${all_aliases[@]})")
|
||||
fi
|
||||
if "$repro"; then
|
||||
clojure_args+=("-Srepro")
|
||||
fi
|
||||
if "$force"; then
|
||||
clojure_args+=("-Sforce")
|
||||
fi
|
||||
|
||||
if "$pom"; then
|
||||
if "$verbose"; then
|
||||
clojure_args+=("-Sverbose")
|
||||
fi
|
||||
"$CLOJURE_CMD" "${clojure_args[@]}" -Spom
|
||||
elif "$describe"; then
|
||||
if "$verbose"; then
|
||||
clojure_args+=("-Sverbose")
|
||||
fi
|
||||
"$CLOJURE_CMD" "${clojure_args[@]}" -Sdescribe
|
||||
elif "$tree"; then
|
||||
if "$verbose"; then
|
||||
clojure_args+=("-Sverbose")
|
||||
fi
|
||||
"$CLOJURE_CMD" "${clojure_args[@]}" -Stree
|
||||
else
|
||||
set -f
|
||||
if [[ -n "$force_cp" ]]; then
|
||||
cp="$force_cp"
|
||||
else
|
||||
if "$verbose"; then
|
||||
"$CLOJURE_CMD" "${clojure_args[@]}" -Sverbose -e nil
|
||||
fi
|
||||
cp=`"$CLOJURE_CMD" "${clojure_args[@]}" -Spath`
|
||||
fi
|
||||
if "$print_classpath"; then
|
||||
echo $cp
|
||||
else
|
||||
if [[ ${#main_aliases[@]} -gt 0 ]] || [[ ${#all_aliases[@]} -gt 0 ]]; then
|
||||
# Attempt to extract the main cache filename by parsing the output of -Sverbose
|
||||
cp_file=`"$CLOJURE_CMD" "${clojure_args[@]}" -Sverbose -Spath | grep cp_file | cut -d = -f 2 | sed 's/^ *//g'`
|
||||
main_file="${cp_file%.cp}.main"
|
||||
fi
|
||||
if [[ -e "$main_file" ]]; then
|
||||
main_cache_opts=($(cat "$main_file"))
|
||||
fi
|
||||
exec bb --classpath "$cp" "${main_cache_opts[@]}" "$@"
|
||||
fi
|
||||
fi
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
(ns babashka.impl.Boolean
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [list]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn parseBoolean [^String x]
|
||||
(Boolean/parseBoolean x))
|
||||
|
||||
(def boolean-bindings
|
||||
{'Boolean/parseBoolean parseBoolean})
|
||||
|
||||
(comment
|
||||
|
||||
)
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
(ns babashka.impl.Double
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [list]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn parseDouble [^String x]
|
||||
(Double/parseDouble x))
|
||||
|
||||
(def double-bindings
|
||||
{'Double/parseDouble parseDouble})
|
||||
|
||||
(comment
|
||||
|
||||
)
|
||||
|
|
@ -11,4 +11,8 @@
|
|||
'generate-smile json/generate-smile
|
||||
'decode json/decode
|
||||
'parse-string json/parse-string
|
||||
'parse-smile json/parse-smile
|
||||
'parse-stream json/parse-stream
|
||||
'parsed-seq json/parsed-seq
|
||||
'parsed-smile-seq json/parsed-smile-seq
|
||||
'decode-smile json/decode-smile})
|
||||
|
|
|
|||
232
src/babashka/impl/classes.clj
Normal file
232
src/babashka/impl/classes.clj
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
(ns babashka.impl.classes
|
||||
{:no-doc true}
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
#_[clojure.string :as str]))
|
||||
|
||||
;; (def os-name (str/lower-case (System/getProperty "os.name")))
|
||||
;; (def os (cond (str/includes? os-name "mac") :mac
|
||||
;; (or (str/includes? os-name "nix")
|
||||
;; (str/includes? os-name "nux")) :linux
|
||||
;; (str/includes? os-name "win") :windows))
|
||||
;; (def unix-like? (or (identical? os :linux)
|
||||
;; (identical? os :mac)))
|
||||
|
||||
(def classes
|
||||
'{:all [java.io.BufferedReader
|
||||
java.io.BufferedWriter
|
||||
java.io.ByteArrayInputStream
|
||||
java.io.ByteArrayOutputStream
|
||||
java.io.File
|
||||
java.io.InputStream
|
||||
java.io.IOException
|
||||
java.io.OutputStream
|
||||
java.io.StringReader
|
||||
java.io.StringWriter
|
||||
java.lang.ArithmeticException
|
||||
java.lang.AssertionError
|
||||
java.lang.Boolean
|
||||
java.lang.Class
|
||||
java.lang.Double
|
||||
java.lang.Exception
|
||||
java.lang.Integer
|
||||
java.lang.Math
|
||||
java.util.concurrent.LinkedBlockingQueue
|
||||
java.lang.Object
|
||||
java.lang.String
|
||||
java.lang.System
|
||||
java.lang.Throwable
|
||||
java.lang.Process
|
||||
java.lang.ProcessBuilder
|
||||
java.lang.ProcessBuilder$Redirect
|
||||
java.net.URI
|
||||
java.net.HttpURLConnection
|
||||
java.net.ServerSocket
|
||||
java.net.Socket
|
||||
java.net.UnknownHostException
|
||||
java.net.URLEncoder
|
||||
java.net.URLDecoder
|
||||
java.nio.file.CopyOption
|
||||
java.nio.file.FileAlreadyExistsException
|
||||
java.nio.file.Files
|
||||
java.nio.file.LinkOption
|
||||
java.nio.file.NoSuchFileException
|
||||
java.nio.file.Path
|
||||
java.nio.file.Paths
|
||||
java.nio.file.StandardCopyOption
|
||||
java.nio.file.attribute.FileAttribute
|
||||
java.nio.file.attribute.FileTime
|
||||
java.nio.file.attribute.PosixFilePermission
|
||||
java.nio.file.attribute.PosixFilePermissions
|
||||
java.time.format.DateTimeFormatter
|
||||
java.time.Clock
|
||||
java.time.DateTimeException
|
||||
java.time.DayOfWeek
|
||||
java.time.Duration
|
||||
java.time.Instant
|
||||
java.time.LocalDate
|
||||
java.time.LocalDateTime
|
||||
java.time.LocalTime
|
||||
java.time.Month
|
||||
java.time.MonthDay
|
||||
java.time.OffsetDateTime
|
||||
java.time.OffsetTime
|
||||
java.time.Period
|
||||
java.time.Year
|
||||
java.time.YearMonth
|
||||
java.time.ZonedDateTime
|
||||
java.time.ZoneId
|
||||
java.time.ZoneOffset
|
||||
java.time.temporal.TemporalAccessor
|
||||
java.util.regex.Pattern
|
||||
java.util.Base64
|
||||
java.util.Base64$Decoder
|
||||
java.util.Base64$Encoder
|
||||
java.util.Date
|
||||
java.util.UUID
|
||||
java.util.concurrent.TimeUnit
|
||||
java.util.zip.InflaterInputStream
|
||||
java.util.zip.DeflaterInputStream
|
||||
java.util.zip.GZIPInputStream
|
||||
java.util.zip.GZIPOutputStream]
|
||||
:constructors [clojure.lang.Delay
|
||||
clojure.lang.MapEntry
|
||||
clojure.lang.LineNumberingPushbackReader]
|
||||
:methods [borkdude.graal.LockFix ;; support for locking
|
||||
]
|
||||
:fields [clojure.lang.PersistentQueue]
|
||||
:instance-checks [clojure.lang.ExceptionInfo
|
||||
clojure.lang.IObj
|
||||
clojure.lang.IEditableCollection]
|
||||
:custom {clojure.lang.LineNumberingPushbackReader {:allPublicConstructors true
|
||||
:allPublicMethods true}
|
||||
java.lang.Thread
|
||||
{:allPublicConstructors true
|
||||
;; generated with `public-declared-method-names`, see in
|
||||
;; `comment` below
|
||||
:methods [{:name "activeCount"}
|
||||
{:name "checkAccess"}
|
||||
{:name "currentThread"}
|
||||
{:name "dumpStack"}
|
||||
{:name "enumerate"}
|
||||
{:name "getAllStackTraces"}
|
||||
{:name "getContextClassLoader"}
|
||||
{:name "getDefaultUncaughtExceptionHandler"}
|
||||
{:name "getId"}
|
||||
{:name "getName"}
|
||||
{:name "getPriority"}
|
||||
{:name "getStackTrace"}
|
||||
{:name "getState"}
|
||||
{:name "getThreadGroup"}
|
||||
{:name "getUncaughtExceptionHandler"}
|
||||
{:name "holdsLock"}
|
||||
{:name "interrupt"}
|
||||
{:name "interrupted"}
|
||||
{:name "isAlive"}
|
||||
{:name "isDaemon"}
|
||||
{:name "isInterrupted"}
|
||||
{:name "join"}
|
||||
{:name "run"}
|
||||
{:name "setContextClassLoader"}
|
||||
{:name "setDaemon"}
|
||||
{:name "setDefaultUncaughtExceptionHandler"}
|
||||
{:name "setName"}
|
||||
{:name "setPriority"}
|
||||
{:name "setUncaughtExceptionHandler"}
|
||||
{:name "sleep"}
|
||||
{:name "start"}
|
||||
{:name "toString"}
|
||||
{:name "yield"}]}
|
||||
java.net.URL
|
||||
{:allPublicConstructors true
|
||||
:allPublicFields true
|
||||
;; generated with `public-declared-method-names`, see in
|
||||
;; `comment` below
|
||||
:methods [{:name "equals"}
|
||||
{:name "getAuthority"}
|
||||
{:name "getContent"}
|
||||
{:name "getDefaultPort"}
|
||||
{:name "getFile"}
|
||||
{:name "getHost"}
|
||||
{:name "getPath"}
|
||||
{:name "getPort"}
|
||||
{:name "getProtocol"}
|
||||
{:name "getQuery"}
|
||||
{:name "getRef"}
|
||||
{:name "getUserInfo"}
|
||||
{:name "hashCode"}
|
||||
{:name "openConnection"}
|
||||
{:name "openStream"}
|
||||
{:name "sameFile"}
|
||||
;; not supported: {:name "setURLStreamHandlerFactory"}
|
||||
{:name "toExternalForm"}
|
||||
{:name "toString"}
|
||||
{:name "toURI"}]}}})
|
||||
|
||||
(defmacro gen-class-map []
|
||||
(let [classes (concat (:all classes)
|
||||
(keys (:custom classes))
|
||||
(:constructors classes)
|
||||
(:methods classes)
|
||||
(:fields classes)
|
||||
(:instance-checks classes))
|
||||
m (apply hash-map
|
||||
(for [c classes
|
||||
c [(list 'quote c) c]]
|
||||
c))]
|
||||
(assoc m :public-class
|
||||
(fn [v]
|
||||
(cond (instance? java.nio.file.Path v)
|
||||
java.nio.file.Path
|
||||
(instance? java.lang.Process v)
|
||||
java.lang.Process)))))
|
||||
|
||||
(def class-map (gen-class-map))
|
||||
|
||||
(defn generate-reflection-file
|
||||
"Generate reflection.json file"
|
||||
[& args]
|
||||
(let [entries (vec (for [c (sort (:all classes))
|
||||
:let [class-name (str c)]]
|
||||
{:name class-name
|
||||
:allPublicMethods true
|
||||
:allPublicFields true
|
||||
:allPublicConstructors true}))
|
||||
constructors (vec (for [c (sort (:constructors classes))
|
||||
:let [class-name (str c)]]
|
||||
{:name class-name
|
||||
:allPublicConstructors true}))
|
||||
methods (vec (for [c (sort (:methods classes))
|
||||
:let [class-name (str c)]]
|
||||
{:name class-name
|
||||
:allPublicMethods true}))
|
||||
fields (vec (for [c (sort (:fields classes))
|
||||
:let [class-name (str c)]]
|
||||
{:name class-name
|
||||
:allPublicFields true}))
|
||||
custom-entries (for [[c v] (:custom classes)
|
||||
:let [class-name (str c)]]
|
||||
(assoc v :name class-name))
|
||||
all-entries (concat entries constructors methods fields custom-entries)]
|
||||
(spit (or
|
||||
(first args)
|
||||
"reflection.json") (json/generate-string all-entries {:pretty true}))))
|
||||
|
||||
(comment
|
||||
|
||||
(defn public-declared-method? [c m]
|
||||
(and (= c (.getDeclaringClass m))
|
||||
(not (.getAnnotation m Deprecated))))
|
||||
|
||||
(defn public-declared-method-names [c]
|
||||
(->> (.getMethods c)
|
||||
(keep (fn [m]
|
||||
(when (public-declared-method? c m)
|
||||
{:name (.getName m)})) )
|
||||
(distinct)
|
||||
(sort-by :name)
|
||||
(vec)))
|
||||
|
||||
(public-declared-method-names java.lang.UNIXProcess)
|
||||
(public-declared-method-names java.net.URL)
|
||||
)
|
||||
|
|
@ -7,29 +7,37 @@
|
|||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defprotocol IResourceResolver
|
||||
(getResource [this path]))
|
||||
(getResource [this path opts]))
|
||||
|
||||
(deftype DirectoryResolver [path]
|
||||
IResourceResolver
|
||||
(getResource [this resource-path]
|
||||
(getResource [this resource-path {:keys [:url?]}]
|
||||
(let [f (io/file path resource-path)]
|
||||
(when (.exists f)
|
||||
(slurp f)))))
|
||||
(if url?
|
||||
(java.net.URL. (str "file:"
|
||||
(.getCanonicalPath f)))
|
||||
{:file (.getCanonicalPath f)
|
||||
:source (slurp f)})))))
|
||||
|
||||
(defn path-from-jar
|
||||
[^java.io.File jar-file path]
|
||||
[^java.io.File jar-file path {:keys [:url?]}]
|
||||
(with-open [jar (JarFile. jar-file)]
|
||||
(let [entries (enumeration-seq (.entries jar))
|
||||
entry (some (fn [^JarFile$JarFileEntry x]
|
||||
(let [nm (.getName x)]
|
||||
(when (and (not (.isDirectory x)) (= path nm))
|
||||
(slurp (.getInputStream jar x))))) entries)]
|
||||
(if url?
|
||||
(java.net.URL.
|
||||
(str "jar:file:" (.getCanonicalPath jar-file) "!/" path))
|
||||
{:file path
|
||||
:source (slurp (.getInputStream jar x))})))) entries)]
|
||||
entry)))
|
||||
|
||||
(deftype JarFileResolver [path]
|
||||
IResourceResolver
|
||||
(getResource [this resource-path]
|
||||
(path-from-jar path resource-path)))
|
||||
(getResource [this resource-path opts]
|
||||
(path-from-jar path resource-path opts)))
|
||||
|
||||
(defn part->entry [part]
|
||||
(if (str/ends-with? part ".jar")
|
||||
|
|
@ -38,25 +46,25 @@
|
|||
|
||||
(deftype Loader [entries]
|
||||
IResourceResolver
|
||||
(getResource [this resource-path]
|
||||
(some #(getResource % resource-path) entries)))
|
||||
(getResource [this resource-path opts]
|
||||
(some #(getResource % resource-path opts) entries)))
|
||||
|
||||
(defn loader [^String classpath]
|
||||
(let [parts (.split classpath (System/getProperty "path.separator"))
|
||||
entries (map part->entry parts)]
|
||||
(Loader. entries)))
|
||||
|
||||
(defn source-for-namespace [loader namespace]
|
||||
(defn source-for-namespace [loader namespace opts]
|
||||
(let [ns-str (name namespace)
|
||||
^String ns-str (munge ns-str)
|
||||
path (.replace ns-str "." (System/getProperty "file.separator"))
|
||||
paths (map #(str path %) [".bb" ".clj" ".cljc"])]
|
||||
(some #(getResource loader %) paths)))
|
||||
(some #(getResource loader % opts) paths)))
|
||||
|
||||
;;;; Scratch
|
||||
|
||||
(comment
|
||||
(def l (loader "src:/Users/borkdude/.m2/repository/cheshire/cheshire/5.9.0/cheshire-5.9.0.jar"))
|
||||
(source-for-namespace l 'babashka.impl.cheshire)
|
||||
(source-for-namespace l 'cheshire.core)
|
||||
(source-for-namespace l 'babashka.impl.cheshire nil)
|
||||
(:file (source-for-namespace l 'cheshire.core nil))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
(ns babashka.impl.clojure.core
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [future]))
|
||||
(:refer-clojure :exclude [future])
|
||||
(:require [borkdude.graal.locking :as locking]))
|
||||
|
||||
(defn locking* [form bindings v f & args]
|
||||
(apply @#'locking/locking form bindings v f args))
|
||||
|
||||
(def core-extras
|
||||
{'file-seq file-seq
|
||||
'agent agent
|
||||
'instance? instance? ;; TODO: move to sci
|
||||
'send send
|
||||
'send-off send-off
|
||||
'promise promise
|
||||
'deliver deliver
|
||||
'locking (with-meta locking* {:sci/macro true})
|
||||
'shutdown-agents shutdown-agents
|
||||
'slurp slurp
|
||||
'spit spit})
|
||||
'spit spit
|
||||
'Throwable->map Throwable->map
|
||||
'compare-and-set! compare-and-set!})
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@
|
|||
:no-doc true}
|
||||
babashka.impl.clojure.core.server
|
||||
(:refer-clojure :exclude [locking])
|
||||
(:require [sci.core :as sci])
|
||||
(:import
|
||||
[clojure.lang LineNumberingPushbackReader]
|
||||
[java.net InetAddress Socket ServerSocket SocketException]
|
||||
[java.io Reader Writer PrintWriter BufferedWriter BufferedReader InputStreamReader OutputStreamWriter]))
|
||||
[java.io BufferedWriter InputStreamReader OutputStreamWriter]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
|
|
@ -41,9 +42,9 @@
|
|||
args - to pass to accept-fn"
|
||||
[^Socket conn client-id in out err accept args]
|
||||
(try
|
||||
(binding [*in* in
|
||||
*out* out
|
||||
*err* err]
|
||||
(sci/with-bindings {sci/in in
|
||||
sci/out out
|
||||
sci/err err}
|
||||
(swap! server assoc-in [:sessions client-id] {})
|
||||
(apply accept args))
|
||||
(catch SocketException _disconnect)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
(ns babashka.impl.clojure.java.io
|
||||
{:no-doc true}
|
||||
(:require [clojure.java.io :as io]))
|
||||
|
||||
(def io-namespace
|
||||
{'as-relative-path io/as-relative-path
|
||||
'as-url io/as-url
|
||||
'copy io/copy
|
||||
'delete-file io/delete-file
|
||||
'file io/file
|
||||
|
|
|
|||
42
src/babashka/impl/clojure/java/shell.clj
Normal file
42
src/babashka/impl/clojure/java/shell.clj
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(ns babashka.impl.clojure.java.shell
|
||||
{:no-doc true}
|
||||
(:require [clojure.java.shell :as shell]
|
||||
[sci.core :as sci]))
|
||||
|
||||
(def sh-dir (sci/new-dynamic-var '*sh-dir* nil))
|
||||
(def sh-env (sci/new-dynamic-var '*sh-env* nil))
|
||||
|
||||
(defn with-sh-dir*
|
||||
[_ _ dir & forms]
|
||||
`(binding [clojure.java.shell/*sh-dir* ~dir]
|
||||
~@forms))
|
||||
|
||||
(defn with-sh-env*
|
||||
[_ _ env & forms]
|
||||
`(binding [clojure.java.shell/*sh-env* ~env]
|
||||
~@forms))
|
||||
|
||||
(defn parse-args
|
||||
[args]
|
||||
(let [default-encoding "UTF-8" ;; see sh doc string
|
||||
default-opts {:out-enc default-encoding
|
||||
:in-enc default-encoding
|
||||
:dir @sh-dir
|
||||
:env @sh-env}
|
||||
[cmd opts] (split-with string? args)
|
||||
opts (merge default-opts (apply hash-map opts))
|
||||
opts-seq (apply concat opts)]
|
||||
(concat cmd opts-seq)))
|
||||
|
||||
(defn sh [& args]
|
||||
(let [args (parse-args args)]
|
||||
(apply shell/sh args)))
|
||||
|
||||
(def shell-namespace
|
||||
{'*sh-dir* sh-dir
|
||||
'*sh-env* sh-env
|
||||
'with-sh-dir (with-meta with-sh-dir*
|
||||
{:sci/macro true})
|
||||
'with-sh-env (with-meta with-sh-env*
|
||||
{:sci/macro true})
|
||||
'sh sh})
|
||||
|
|
@ -15,9 +15,13 @@
|
|||
:author "Stephen C. Gilardi and Rich Hickey"
|
||||
:no-doc true}
|
||||
babashka.impl.clojure.main
|
||||
(:refer-clojure :exclude [with-bindings])
|
||||
(:import (java.io StringReader)
|
||||
(clojure.lang LineNumberingPushbackReader LispReader$ReaderException)))
|
||||
(:refer-clojure :exclude [with-bindings]))
|
||||
|
||||
(defn demunge
|
||||
"Given a string representation of a fn class,
|
||||
as in a stack trace element, returns a readable version."
|
||||
[fn-name]
|
||||
(clojure.lang.Compiler/demunge fn-name))
|
||||
|
||||
(defmacro with-bindings
|
||||
"Executes body in the context of thread-local bindings for several vars
|
||||
|
|
@ -44,18 +48,6 @@
|
|||
*e nil]
|
||||
~@body))
|
||||
|
||||
(defn repl-prompt
|
||||
"Default :prompt hook for repl"
|
||||
[]
|
||||
(print "bb=> " ))
|
||||
|
||||
(defn repl-caught
|
||||
"Default :caught hook for repl"
|
||||
[e]
|
||||
(binding [*out* *err*]
|
||||
(println (.getMessage ^Exception e))
|
||||
(flush)))
|
||||
|
||||
(defn repl
|
||||
"Generic, reusable, read-eval-print loop. By default, reads from *in*,
|
||||
writes to *out*, and prints exception summaries to *err*. If you use the
|
||||
|
|
@ -92,14 +84,7 @@
|
|||
read, eval, or print throws an exception or error
|
||||
default: repl-caught"
|
||||
[& options]
|
||||
(let [{:keys [init need-prompt prompt flush read eval print caught]
|
||||
:or {need-prompt (if (instance? LineNumberingPushbackReader *in*)
|
||||
#(.atLineStart ^LineNumberingPushbackReader *in*)
|
||||
#(identity true))
|
||||
prompt repl-prompt
|
||||
flush flush
|
||||
print prn
|
||||
caught repl-caught}}
|
||||
(let [{:keys [init need-prompt prompt flush read eval print caught]}
|
||||
(apply hash-map options)
|
||||
request-prompt (Object.)
|
||||
request-exit (Object.)
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@
|
|||
(print "Caused by: " )
|
||||
(recur cause n))))
|
||||
|
||||
(defn e
|
||||
"REPL utility. Prints a brief stack trace for the root cause of the
|
||||
most recent exception."
|
||||
{:added "1.1"}
|
||||
[]
|
||||
(print-stack-trace (root-cause *e) 8))
|
||||
(def stacktrace-namespace
|
||||
{'root-cause root-cause
|
||||
'print-trace-element print-trace-element
|
||||
'print-throwable print-throwable
|
||||
'print-stack-trace print-stack-trace
|
||||
'print-cause-trace print-cause-trace})
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
(ns babashka.impl.conch
|
||||
{:no-doc true}
|
||||
(:require
|
||||
[babashka.impl.me.raynes.conch.low-level :as ll]))
|
||||
|
||||
(def conch-namespace
|
||||
{;; low level API
|
||||
'proc ll/proc
|
||||
'destroy ll/destroy
|
||||
'exit-code ll/exit-code
|
||||
'flush ll/flush
|
||||
'done ll/done
|
||||
'stream-to ll/stream-to
|
||||
'feed-from ll/feed-from
|
||||
'stream-to-string ll/stream-to-string
|
||||
'stream-to-out ll/stream-to-out
|
||||
'feed-from-string ll/feed-from-string
|
||||
'read-line ll/read-line})
|
||||
|
|
@ -1,7 +1 @@
|
|||
(ns babashka.impl.exceptions)
|
||||
|
||||
(def exception-bindings
|
||||
{'ArithmeticException ArithmeticException
|
||||
'java.lang.ArithmeticException ArithmeticException
|
||||
'java.lang.AssertionError AssertionError
|
||||
'AssertionError AssertionError})
|
||||
(ns babashka.impl.exceptions)
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
;; From https://github.com/clj-commons/conch
|
||||
|
||||
(ns babashka.impl.me.raynes.conch.low-level
|
||||
"A simple but flexible library for shelling out from Clojure."
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [flush read-line])
|
||||
(:require [clojure.java.io :as io])
|
||||
(:import [java.util.concurrent TimeUnit TimeoutException]
|
||||
[java.io InputStream OutputStream]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn proc
|
||||
"Spin off another process. Returns the process's input stream,
|
||||
output stream, and err stream as a map of :in, :out, and :err keys
|
||||
If passed the optional :dir and/or :env keyword options, the dir
|
||||
and enviroment will be set to what you specify. If you pass
|
||||
:verbose and it is true, commands will be printed. If it is set to
|
||||
:very, environment variables passed, dir, and the command will be
|
||||
printed. If passed the :clear-env keyword option, then the process
|
||||
will not inherit its environment from its parent process."
|
||||
[& args]
|
||||
(let [[cmd args] (split-with (complement keyword?) args)
|
||||
args (apply hash-map args)
|
||||
builder (ProcessBuilder. ^"[Ljava.lang.String;" (into-array String cmd))
|
||||
env (.environment builder)]
|
||||
(when (:clear-env args)
|
||||
(.clear env))
|
||||
(doseq [[k v] (:env args)]
|
||||
(.put env k v))
|
||||
(when-let [dir (:dir args)]
|
||||
(.directory builder (io/file dir)))
|
||||
(when (:verbose args) (apply println cmd))
|
||||
(when (= :very (:verbose args))
|
||||
(when-let [env (:env args)] (prn env))
|
||||
(when-let [dir (:dir args)] (prn dir)))
|
||||
(when (:redirect-err args)
|
||||
(.redirectErrorStream builder true))
|
||||
(let [process (.start builder)]
|
||||
{:out (.getInputStream process)
|
||||
:in (.getOutputStream process)
|
||||
:err (.getErrorStream process)
|
||||
:process process})))
|
||||
|
||||
(defn destroy
|
||||
"Destroy a process."
|
||||
[process]
|
||||
(.destroy ^Process (:process process)))
|
||||
|
||||
;; .waitFor returns the exit code. This makes this function useful for
|
||||
;; both getting an exit code and stopping the thread until a process
|
||||
;; terminates.
|
||||
(defn exit-code
|
||||
"Waits for the process to terminate (blocking the thread) and returns
|
||||
the exit code. If timeout is passed, it is assumed to be milliseconds
|
||||
to wait for the process to exit. If it does not exit in time, it is
|
||||
killed (with or without fire)."
|
||||
([process] (.waitFor ^Process (:process process)))
|
||||
([process timeout]
|
||||
(try
|
||||
(let [^java.util.concurrent.Future fut
|
||||
(future (.waitFor ^Process (:process process)))]
|
||||
(.get fut timeout TimeUnit/MILLISECONDS))
|
||||
(catch Exception e
|
||||
(if (or (instance? TimeoutException e)
|
||||
(instance? TimeoutException (.getCause e)))
|
||||
(do (destroy process)
|
||||
:timeout)
|
||||
(throw e))))))
|
||||
|
||||
(defn flush
|
||||
"Flush the output stream of a process."
|
||||
[process]
|
||||
(let [^OutputStream in (:in process)]
|
||||
(.flush in)))
|
||||
|
||||
(defn done
|
||||
"Close the process's output stream (sending EOF)."
|
||||
[proc]
|
||||
(let [^OutputStream in (:in proc)]
|
||||
(.close in)))
|
||||
|
||||
(defn stream-to
|
||||
"Stream :out or :err from a process to an ouput stream.
|
||||
Options passed are fed to clojure.java.io/copy. They are :encoding to
|
||||
set the encoding and :buffer-size to set the size of the buffer.
|
||||
:encoding defaults to UTF-8 and :buffer-size to 1024."
|
||||
[process from to & args]
|
||||
(apply io/copy (process from) to args))
|
||||
|
||||
(defn feed-from
|
||||
"Feed to a process's input stream with optional. Options passed are
|
||||
fed to clojure.java.io/copy. They are :encoding to set the encoding
|
||||
and :buffer-size to set the size of the buffer. :encoding defaults to
|
||||
UTF-8 and :buffer-size to 1024. If :flush is specified and is false,
|
||||
the process will be flushed after writing."
|
||||
[process from & {flush? :flush :or {flush? true} :as all}]
|
||||
(apply io/copy from (:in process) all)
|
||||
(when flush? (flush process)))
|
||||
|
||||
(defn stream-to-string
|
||||
"Streams the output of the process to a string and returns it."
|
||||
[process from & args]
|
||||
(with-open [writer (java.io.StringWriter.)]
|
||||
(apply stream-to process from writer args)
|
||||
(str writer)))
|
||||
|
||||
;; The writer that Clojure wraps System/out in for *out* seems to buffer
|
||||
;; things instead of writing them immediately. This wont work if you
|
||||
;; really want to stream stuff, so we'll just skip it and throw our data
|
||||
;; directly at System/out.
|
||||
(defn stream-to-out
|
||||
"Streams the output of the process to System/out"
|
||||
[process from & args]
|
||||
(apply stream-to process from (System/out) args))
|
||||
|
||||
(defn feed-from-string
|
||||
"Feed the process some data from a string."
|
||||
[process s & args]
|
||||
(apply feed-from process (java.io.StringReader. s) args))
|
||||
|
||||
(defn read-line
|
||||
"Read a line from a process' :out or :err."
|
||||
[process from]
|
||||
(binding [*in* (io/reader (from process))]
|
||||
(clojure.core/read-line)))
|
||||
|
|
@ -5,50 +5,72 @@
|
|||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[clojure.tools.reader.reader-types :as r]
|
||||
[sci.core :as sci]
|
||||
[sci.impl.interpreter :refer [eval-form]]
|
||||
[sci.impl.opts :refer [init]]
|
||||
[sci.impl.parser :as parser]))
|
||||
[sci.impl.parser :as parser]
|
||||
[sci.core :as sci]
|
||||
[sci.impl.io :as sio]))
|
||||
|
||||
(defn repl-caught
|
||||
"Default :caught hook for repl"
|
||||
[e]
|
||||
(sci/with-bindings {sci/out @sci/err}
|
||||
(sio/println (.getMessage ^Exception e))
|
||||
(sio/flush)))
|
||||
|
||||
(defn repl
|
||||
"REPL with predefined hooks for attachable socket server."
|
||||
[sci-ctx]
|
||||
(let [in (r/indexing-push-back-reader (r/push-back-reader *in*))]
|
||||
(m/repl
|
||||
:init #(do (println "Babashka"
|
||||
(str "v" (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
|
||||
"REPL.")
|
||||
(println "Use :repl/quit or :repl/exit to quit the REPL.")
|
||||
(println "Clojure rocks, Bash reaches.")
|
||||
(println))
|
||||
:read (fn [_request-prompt request-exit]
|
||||
(if (r/peek-char in) ;; if this is nil, we reached EOF
|
||||
(let [v (parser/parse-next sci-ctx in)]
|
||||
(if (or (identical? :repl/quit v)
|
||||
(identical? :repl/exit v)
|
||||
(identical? :edamame.impl.parser/eof v))
|
||||
request-exit
|
||||
v))
|
||||
request-exit))
|
||||
:eval (fn [expr]
|
||||
(let [ret (sci/with-bindings {sci/in *in*
|
||||
sci/out *out*
|
||||
sci/err *err*}
|
||||
(eval-form (update sci-ctx
|
||||
:env
|
||||
(fn [env]
|
||||
(swap! env update-in [:namespaces 'clojure.core]
|
||||
assoc
|
||||
'*1 *1
|
||||
'*2 *2
|
||||
'*3 *3
|
||||
'*e *e)
|
||||
env))
|
||||
expr))]
|
||||
ret))
|
||||
:need-prompt (fn [] true)
|
||||
:prompt #(printf "%s=> " (-> sci-ctx :env deref :current-ns)))))
|
||||
([sci-ctx] (repl sci-ctx nil))
|
||||
([sci-ctx {:keys [:init :read :eval :need-prompt :prompt :flush :print :caught]}]
|
||||
(let [in (r/indexing-push-back-reader (r/push-back-reader @sci/in))]
|
||||
(m/repl
|
||||
:init (or init
|
||||
#(do (sio/println "Babashka"
|
||||
(str "v" (str/trim (slurp (io/resource "BABASHKA_VERSION"))))
|
||||
"REPL.")
|
||||
(sio/println "Use :repl/quit or :repl/exit to quit the REPL.")
|
||||
(sio/println "Clojure rocks, Bash reaches.")
|
||||
(sio/println)))
|
||||
:read (or read
|
||||
(fn [_request-prompt request-exit]
|
||||
;; (prn "PEEK" @sci/in (r/peek-char @sci/in))
|
||||
;; (prn "PEEK" @sci/in (r/peek-char @sci/in)) this works fine
|
||||
(if (r/peek-char in) ;; if this is nil, we reached EOF
|
||||
(let [v (parser/parse-next sci-ctx in)]
|
||||
(if (or (identical? :repl/quit v)
|
||||
(identical? :repl/exit v)
|
||||
(identical? :edamame.impl.parser/eof v))
|
||||
request-exit
|
||||
v))
|
||||
request-exit)))
|
||||
:eval (or eval
|
||||
(fn [expr]
|
||||
(let [ret (eval-form (update sci-ctx
|
||||
:env
|
||||
(fn [env]
|
||||
(swap! env update-in [:namespaces 'clojure.core]
|
||||
assoc
|
||||
'*1 *1
|
||||
'*2 *2
|
||||
'*3 *3
|
||||
'*e *e)
|
||||
env))
|
||||
expr)]
|
||||
ret)))
|
||||
:need-prompt (or need-prompt (fn [] true))
|
||||
:prompt (or prompt #(sio/printf "%s=> " (-> sci-ctx :env deref :current-ns)))
|
||||
:flush (or flush sio/flush)
|
||||
:print (or print sio/prn)
|
||||
:caught (or caught repl-caught)))))
|
||||
|
||||
(defn start-repl! [ctx]
|
||||
(let [sci-ctx (init ctx)]
|
||||
(repl sci-ctx)))
|
||||
(defn start-repl!
|
||||
([sci-ctx] (start-repl! sci-ctx nil))
|
||||
([sci-ctx opts]
|
||||
(repl sci-ctx opts)))
|
||||
|
||||
;;;; Scratch
|
||||
|
||||
(comment
|
||||
(def in (-> (java.io.StringReader. "(+ 1 2 3)") clojure.lang.LineNumberingPushbackReader.))
|
||||
(r/peek-char in)
|
||||
(r/read-char in)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,19 +3,17 @@
|
|||
(:require
|
||||
[babashka.impl.clojure.core.server :as server]
|
||||
[babashka.impl.repl :as repl]
|
||||
[clojure.string :as str]
|
||||
[sci.impl.opts :refer [init]]))
|
||||
[clojure.string :as str]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn start-repl! [host+port sci-opts]
|
||||
(defn start-repl! [host+port sci-ctx]
|
||||
(let [parts (str/split host+port #":")
|
||||
[host port] (if (= 1 (count parts))
|
||||
[nil (Integer. ^String (first parts))]
|
||||
[(first parts) (Integer. ^String (second parts))])
|
||||
host+port (if-not host (str "localhost:" port)
|
||||
host+port)
|
||||
sci-ctx (init sci-opts)
|
||||
socket (server/start-server
|
||||
{:address host
|
||||
:port port
|
||||
|
|
@ -29,7 +27,6 @@
|
|||
(server/stop-server))
|
||||
|
||||
(comment
|
||||
(def sock (start-repl! "0.0.0.0:1666" {:env (atom {})}))
|
||||
@#'server/servers
|
||||
(stop-repl!)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
(ns babashka.impl.utils
|
||||
{:no-doc true}
|
||||
(:require [sci.core :as sci]))
|
||||
|
||||
(defn eval-string [expr ctx]
|
||||
(sci/with-bindings {sci/out *out*
|
||||
sci/in *in*
|
||||
sci/err *err*}
|
||||
(sci/eval-string expr ctx)))
|
||||
|
|
@ -3,26 +3,34 @@
|
|||
(:require
|
||||
[babashka.impl.async :refer [async-namespace]]
|
||||
[babashka.impl.cheshire :refer [cheshire-core-namespace]]
|
||||
[babashka.impl.classes :as classes]
|
||||
[babashka.impl.classpath :as cp]
|
||||
[babashka.impl.clojure.core :refer [core-extras]]
|
||||
[babashka.impl.clojure.java.io :refer [io-namespace]]
|
||||
[babashka.impl.clojure.stacktrace :refer [print-stack-trace]]
|
||||
[babashka.impl.conch :refer [conch-namespace]]
|
||||
[babashka.impl.clojure.java.shell :refer [shell-namespace]]
|
||||
[babashka.impl.clojure.main :refer [demunge]]
|
||||
[babashka.impl.clojure.stacktrace :refer [stacktrace-namespace print-stack-trace]]
|
||||
[babashka.impl.csv :as csv]
|
||||
[babashka.impl.xml :as xml]
|
||||
[babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]]
|
||||
[babashka.impl.repl :as repl]
|
||||
[babashka.impl.socket-repl :as socket-repl]
|
||||
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
||||
[babashka.impl.utils :refer [eval-string]]
|
||||
[babashka.impl.classpath :as cp]
|
||||
[babashka.impl.xml :as xml]
|
||||
[babashka.wait :as wait]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.java.shell :as shell]
|
||||
[clojure.string :as str]
|
||||
[sci.addons :as addons])
|
||||
[sci.addons :as addons]
|
||||
[sci.core :as sci]
|
||||
[sci.impl.interpreter :refer [eval-string*]]
|
||||
[sci.impl.opts :as sci-opts]
|
||||
[sci.impl.vars :as vars])
|
||||
(:gen-class))
|
||||
|
||||
(sci/alter-var-root sci/in (constantly *in*))
|
||||
(sci/alter-var-root sci/out (constantly *out*))
|
||||
(sci/alter-var-root sci/err (constantly *err*))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
;; To detect problems when generating the image, run:
|
||||
;; echo '1' | java -agentlib:native-image-agent=config-output-dir=/tmp -jar target/babashka-xxx-standalone.jar '...'
|
||||
|
|
@ -31,77 +39,83 @@
|
|||
(defn parse-opts [options]
|
||||
(let [opts (loop [options options
|
||||
opts-map {}]
|
||||
(if-let [opt (first options)]
|
||||
(case opt
|
||||
("--version") {:version true}
|
||||
("--help" "-h" "-?") {:help? true}
|
||||
("--verbose")(recur (rest options)
|
||||
(if options
|
||||
(let [opt (first options)]
|
||||
(case opt
|
||||
("--version") {:version true}
|
||||
("--help" "-h" "-?") {:help? true}
|
||||
("--verbose")(recur (next options)
|
||||
(assoc opts-map
|
||||
:verbose? true))
|
||||
("--stream") (recur (next options)
|
||||
(assoc opts-map
|
||||
:stream? true))
|
||||
("--time") (recur (next options)
|
||||
(assoc opts-map
|
||||
:verbose? true))
|
||||
("--stream") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:stream? true))
|
||||
("--time") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:time? true))
|
||||
("-i") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:shell-in true))
|
||||
("-I") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:edn-in true))
|
||||
("-o") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:shell-out true))
|
||||
("-O") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:edn-out true))
|
||||
("-io") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:shell-in true
|
||||
:shell-out true))
|
||||
("-IO") (recur (rest options)
|
||||
(assoc opts-map
|
||||
:edn-in true
|
||||
:edn-out true))
|
||||
("-f" "--file")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map
|
||||
:file (first options))))
|
||||
("--repl")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map
|
||||
:repl true)))
|
||||
("--socket-repl")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map
|
||||
:socket-repl (first options))))
|
||||
("--eval", "-e")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map :expression (first options))))
|
||||
("--classpath", "-cp")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map :classpath (first options))))
|
||||
("--main", "-m")
|
||||
(let [options (rest options)]
|
||||
(recur (rest options)
|
||||
(assoc opts-map :main (first options))))
|
||||
(if (some opts-map [:file :socket-repl :expression :main])
|
||||
(assoc opts-map
|
||||
:command-line-args options)
|
||||
(if (and (not= \( (first (str/trim opt)))
|
||||
(.exists (io/file opt)))
|
||||
:time? 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
|
||||
: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))))
|
||||
("-f" "--file")
|
||||
(let [options (next options)]
|
||||
(recur (next options)
|
||||
(assoc opts-map
|
||||
:file (first options))))
|
||||
("--repl")
|
||||
(let [options (next options)]
|
||||
(recur (next options)
|
||||
(assoc opts-map
|
||||
:repl true)))
|
||||
("--socket-repl")
|
||||
(let [options (next options)]
|
||||
(recur (next options)
|
||||
(assoc opts-map
|
||||
:socket-repl (first options))))
|
||||
("--eval", "-e")
|
||||
(let [options (next options)]
|
||||
(recur (next options)
|
||||
(assoc opts-map :expression (first options))))
|
||||
("--main", "-m")
|
||||
(let [options (next options)]
|
||||
(recur (next options)
|
||||
(assoc opts-map :main (first options))))
|
||||
(if (some opts-map [:file :socket-repl :expression :main])
|
||||
(assoc opts-map
|
||||
:file opt
|
||||
:command-line-args (rest options))
|
||||
(assoc opts-map
|
||||
:expression opt
|
||||
:command-line-args (rest options)))))
|
||||
:command-line-args options)
|
||||
(if (and (not= \( (first (str/trim opt)))
|
||||
(.exists (io/file opt)))
|
||||
(assoc opts-map
|
||||
:file opt
|
||||
:command-line-args (next options))
|
||||
(assoc opts-map
|
||||
:expression opt
|
||||
:command-line-args (next options))))))
|
||||
opts-map))]
|
||||
opts))
|
||||
|
||||
|
|
@ -122,8 +136,9 @@
|
|||
(println (str "babashka v"(str/trim (slurp (io/resource "BABASHKA_VERSION"))))))
|
||||
|
||||
(def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose]
|
||||
[ ( --classpath | -cp ) <cp> ] [ ( --main | -m ) <main-namespace> ]
|
||||
( -e <expression> | -f <file> | --repl | --socket-repl [<host>:]<port> )
|
||||
[ ( --classpath | -cp ) <cp> ] [ --uberscript <file> ]
|
||||
[ ( --main | -m ) <main-namespace> | -e <expression> | -f <file> |
|
||||
--repl | --socket-repl [<host>:]<port> ]
|
||||
[ arg* ]")
|
||||
(defn print-usage []
|
||||
(println usage-string))
|
||||
|
|
@ -136,21 +151,24 @@
|
|||
(println)
|
||||
(println "Options:")
|
||||
(println "
|
||||
--help, -h or -? Print this help text.
|
||||
--version Print the current version of babashka.
|
||||
-i Bind *in* to a lazy seq of lines from stdin.
|
||||
-I Bind *in* to a lazy seq of EDN values from stdin.
|
||||
-o Write lines to stdout.
|
||||
-O Write EDN values to stdout.
|
||||
--verbose Print entire stacktrace in case of exception.
|
||||
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *in* becomes a single value per iteration.
|
||||
-e, --eval <expr> Evaluate an expression.
|
||||
-f, --file <path> Evaluate a file.
|
||||
-cp, --classpath Classpath to use.
|
||||
-m, --main <ns> Call the -main function from namespace with args.
|
||||
--repl Start REPL
|
||||
--socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
||||
--time Print execution time before exiting.
|
||||
--help, -h or -? Print this help text.
|
||||
--version Print the current version of babashka.
|
||||
|
||||
-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.
|
||||
--verbose Print entire stacktrace in case of exception.
|
||||
--stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration.
|
||||
--uberscript <file> Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file.
|
||||
|
||||
-e, --eval <expr> Evaluate an expression.
|
||||
-f, --file <path> Evaluate a file.
|
||||
-cp, --classpath Classpath to use.
|
||||
-m, --main <ns> Call the -main function from namespace with args.
|
||||
--repl Start REPL
|
||||
--socket-repl Start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
||||
--time Print execution time before exiting.
|
||||
|
||||
If neither -e, -f, or --socket-repl are specified, then the first argument that is not parsed as a option is treated as a file if it exists, or as an expression otherwise.
|
||||
Everything after that is bound to *command-line-args*."))
|
||||
|
|
@ -167,28 +185,21 @@ Everything after that is bound to *command-line-args*."))
|
|||
(edn/read {;;:readers *data-readers*
|
||||
:eof ::EOF} *in*))
|
||||
|
||||
(defn load-file* [ctx file]
|
||||
(let [s (slurp file)]
|
||||
(eval-string s ctx)))
|
||||
(def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false))
|
||||
|
||||
(defn eval* [ctx form]
|
||||
(eval-string (pr-str form) ctx))
|
||||
(defn load-file* [sci-ctx f]
|
||||
(let [f (io/file f)
|
||||
s (slurp f)]
|
||||
(sci/with-bindings {vars/file-var (.getCanonicalPath f)}
|
||||
(eval-string* sci-ctx s))))
|
||||
|
||||
(defn start-repl! [ctx read-next]
|
||||
(let [ctx (update ctx :bindings assoc
|
||||
(with-meta '*in*
|
||||
{:sci/deref! true})
|
||||
(read-next))]
|
||||
(repl/start-repl! ctx)))
|
||||
(defn eval* [sci-ctx form]
|
||||
(eval-string* sci-ctx (pr-str form)))
|
||||
|
||||
(defn start-socket-repl! [address ctx read-next]
|
||||
(let [ctx (update ctx :bindings assoc
|
||||
(with-meta '*in*
|
||||
{:sci/deref! true})
|
||||
(read-next))]
|
||||
(socket-repl/start-repl! address ctx)
|
||||
;; hang until SIGINT
|
||||
@(promise)))
|
||||
(defn start-socket-repl! [address ctx]
|
||||
(socket-repl/start-repl! address ctx)
|
||||
;; hang until SIGINT
|
||||
@(promise))
|
||||
|
||||
(defn exit [n]
|
||||
(throw (ex-info "" {:bb/exit-code n})))
|
||||
|
|
@ -197,6 +208,49 @@ Everything after that is bound to *command-line-args*."))
|
|||
;; (sci/set-var-root! sci/*out* *out*)
|
||||
;; (sci/set-var-root! sci/*err* *err*)
|
||||
|
||||
(def aliases
|
||||
'{tools.cli 'clojure.tools.cli
|
||||
edn clojure.edn
|
||||
wait babashka.wait
|
||||
sig babashka.signal
|
||||
shell clojure.java.shell
|
||||
io clojure.java.io
|
||||
async clojure.core.async
|
||||
csv clojure.data.csv
|
||||
json cheshire.core})
|
||||
|
||||
(def namespaces
|
||||
{'clojure.tools.cli tools-cli-namespace
|
||||
'clojure.edn {'read edn/read
|
||||
'read-string edn/read-string}
|
||||
'clojure.java.shell shell-namespace
|
||||
'babashka.wait {'wait-for-port wait/wait-for-port
|
||||
'wait-for-path wait/wait-for-path}
|
||||
'babashka.signal {'pipe-signal-received? pipe-signal-received?}
|
||||
'clojure.java.io io-namespace
|
||||
'clojure.core.async async-namespace
|
||||
'clojure.data.csv csv/csv-namespace
|
||||
'cheshire.core cheshire-core-namespace
|
||||
'clojure.stacktrace stacktrace-namespace
|
||||
'clojure.main {'demunge demunge}
|
||||
'clojure.repl {'demunge demunge}
|
||||
'clojure.data.xml xml/xml-namespace})
|
||||
|
||||
(def bindings
|
||||
{'java.lang.System/exit exit ;; override exit, so we have more control
|
||||
'System/exit exit})
|
||||
|
||||
(defn error-handler* [^Exception e verbose?]
|
||||
(binding [*out* *err*]
|
||||
(let [d (ex-data e)
|
||||
exit-code (:bb/exit-code d)]
|
||||
(if exit-code [nil exit-code]
|
||||
(do (if verbose?
|
||||
(print-stack-trace e)
|
||||
(println (.getMessage e)))
|
||||
(flush)
|
||||
[nil 1])))))
|
||||
|
||||
(defn main
|
||||
[& args]
|
||||
(handle-pipe!)
|
||||
|
|
@ -208,7 +262,7 @@ Everything after that is bound to *command-line-args*."))
|
|||
:expression :stream? :time?
|
||||
:repl :socket-repl
|
||||
:verbose? :classpath
|
||||
:main] :as _opts}
|
||||
:main :uberscript] :as _opts}
|
||||
(parse-opts args)
|
||||
read-next (fn [*in*]
|
||||
(if (pipe-signal-received?)
|
||||
|
|
@ -222,6 +276,7 @@ Everything after that is bound to *command-line-args*."))
|
|||
(edn-seq *in*)
|
||||
:else
|
||||
(edn/read *in*))))))
|
||||
uberscript-sources (atom ())
|
||||
env (atom {})
|
||||
classpath (or classpath
|
||||
(System/getenv "BABASHKA_CLASSPATH"))
|
||||
|
|
@ -229,133 +284,122 @@ Everything after that is bound to *command-line-args*."))
|
|||
(cp/loader classpath))
|
||||
load-fn (when classpath
|
||||
(fn [{:keys [:namespace]}]
|
||||
(cp/source-for-namespace loader namespace)))
|
||||
ctx {:aliases '{tools.cli 'clojure.tools.cli
|
||||
edn clojure.edn
|
||||
wait babashka.wait
|
||||
sig babashka.signal
|
||||
shell clojure.java.shell
|
||||
io clojure.java.io
|
||||
conch me.raynes.conch.low-level
|
||||
async clojure.core.async
|
||||
csv clojure.data.csv
|
||||
json cheshire.core}
|
||||
:namespaces {'clojure.core (assoc core-extras
|
||||
'*command-line-args* command-line-args)
|
||||
'clojure.tools.cli tools-cli-namespace
|
||||
'clojure.edn {'read-string edn/read-string}
|
||||
'clojure.java.shell {'sh shell/sh}
|
||||
'babashka.wait {'wait-for-port wait/wait-for-port
|
||||
'wait-for-path wait/wait-for-path}
|
||||
'babashka.signal {'pipe-signal-received? pipe-signal-received?}
|
||||
'clojure.java.io io-namespace
|
||||
'me.raynes.conch.low-level conch-namespace
|
||||
'clojure.core.async async-namespace
|
||||
'clojure.data.csv csv/csv-namespace
|
||||
'cheshire.core cheshire-core-namespace
|
||||
'clojure.data.xml xml/xml-namespace}
|
||||
:bindings {'java.lang.System/exit exit ;; override exit, so we have more control
|
||||
'System/exit exit}
|
||||
(let [res (cp/source-for-namespace loader namespace nil)]
|
||||
(when uberscript (swap! uberscript-sources conj (:source res)))
|
||||
res)))
|
||||
_ (when file (vars/bindRoot vars/file-var (.getCanonicalPath (io/file file))))
|
||||
ctx {:aliases aliases
|
||||
:namespaces (-> namespaces
|
||||
(assoc 'clojure.core
|
||||
(assoc core-extras
|
||||
'*command-line-args*
|
||||
(sci/new-dynamic-var '*command-line-args* command-line-args)
|
||||
'*file* vars/file-var
|
||||
'*warn-on-reflection* reflection-var))
|
||||
(assoc-in ['clojure.java.io 'resource]
|
||||
#(when classpath (cp/getResource loader % {:url? true}))))
|
||||
:bindings bindings
|
||||
:env env
|
||||
:features #{:bb}
|
||||
:classes {'java.lang.ArithmeticException ArithmeticException
|
||||
'java.lang.AssertionError AssertionError
|
||||
'java.lang.Boolean Boolean
|
||||
'java.io.BufferedWriter java.io.BufferedWriter
|
||||
'java.io.BufferedReader java.io.BufferedReader
|
||||
'java.lang.Class Class
|
||||
'java.lang.Double Double
|
||||
'java.lang.Exception Exception
|
||||
'clojure.lang.ExceptionInfo clojure.lang.ExceptionInfo
|
||||
'java.lang.Integer Integer
|
||||
'java.io.File java.io.File
|
||||
'clojure.lang.LineNumberingPushbackReader clojure.lang.LineNumberingPushbackReader
|
||||
'java.util.regex.Pattern java.util.regex.Pattern
|
||||
'java.lang.String String
|
||||
'java.io.StringReader java.io.StringReader
|
||||
'java.io.StringWriter java.io.StringWriter
|
||||
'java.lang.System System
|
||||
'java.lang.Thread Thread
|
||||
'sun.nio.fs.UnixPath sun.nio.fs.UnixPath
|
||||
'java.nio.file.attribute.FileAttribute java.nio.file.attribute.FileAttribute
|
||||
'java.nio.file.attribute.PosixFilePermission java.nio.file.attribute.PosixFilePermission
|
||||
'java.nio.file.attribute.PosixFilePermissions java.nio.file.attribute.PosixFilePermissions
|
||||
'java.nio.file.CopyOption java.nio.file.CopyOption
|
||||
'java.nio.file.FileAlreadyExistsException java.nio.file.FileAlreadyExistsException
|
||||
'java.nio.file.Files java.nio.file.Files
|
||||
'java.nio.file.NoSuchFileException java.nio.file.NoSuchFileException
|
||||
'java.nio.file.StandardCopyOption java.nio.file.StandardCopyOption
|
||||
}
|
||||
:classes classes/class-map
|
||||
:imports '{ArithmeticException java.lang.ArithmeticException
|
||||
AssertionError java.lang.AssertionError
|
||||
Boolean java.lang.Boolean
|
||||
Class java.lang.Class
|
||||
Double java.lang.Double
|
||||
Exception java.lang.Exception
|
||||
IllegalArgumentException java.lang.IllegalArgumentException
|
||||
Integer java.lang.Integer
|
||||
File java.io.File
|
||||
Math java.lang.Math
|
||||
Object java.lang.Object
|
||||
ProcessBuilder java.lang.ProcessBuilder
|
||||
String java.lang.String
|
||||
System java.lang.System
|
||||
Thread java.lang.Thread}
|
||||
:load-fn load-fn}
|
||||
ctx (update ctx :bindings assoc 'eval #(eval* ctx %)
|
||||
'load-file #(load-file* ctx %))
|
||||
:load-fn load-fn
|
||||
:dry-run uberscript}
|
||||
ctx (addons/future ctx)
|
||||
_preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim) (eval-string ctx))
|
||||
expression (if main
|
||||
(format "(ns user (:require [%1$s])) (apply %1$s/-main *command-line-args*)"
|
||||
main)
|
||||
expression)
|
||||
sci-ctx (sci-opts/init ctx)
|
||||
_ (swap! (:env sci-ctx)
|
||||
(fn [env]
|
||||
(update-in env [:namespaces 'clojure.core] assoc
|
||||
'eval #(eval* sci-ctx %)
|
||||
'load-file #(load-file* sci-ctx %))))
|
||||
_ (swap! (:env sci-ctx)
|
||||
(fn [env]
|
||||
(assoc-in env [:namespaces 'clojure.main 'repl]
|
||||
(fn [& opts]
|
||||
(let [opts (apply hash-map opts)]
|
||||
(repl/start-repl! sci-ctx opts))))))
|
||||
preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim))
|
||||
[expression exit-code]
|
||||
(cond expression [expression nil]
|
||||
main [(format "(ns user (:require [%1$s])) (apply %1$s/-main *command-line-args*)"
|
||||
main) nil]
|
||||
file (try [(read-file file) nil]
|
||||
(catch Exception e
|
||||
(error-handler* e verbose?))))
|
||||
exit-code
|
||||
(or
|
||||
#_(binding [*out* *err*]
|
||||
(prn ">>" _opts))
|
||||
(second
|
||||
(cond version
|
||||
[(print-version) 0]
|
||||
help?
|
||||
[(print-help) 0]
|
||||
repl [(start-repl! ctx #(read-next *in*)) 0]
|
||||
socket-repl [(start-socket-repl! socket-repl ctx #(read-next *in*)) 0]
|
||||
:else
|
||||
(try
|
||||
(let [expr (if file (read-file file) expression)]
|
||||
(if expr
|
||||
(loop [in (read-next *in*)]
|
||||
(let [ctx (update-in ctx [:namespaces 'user] assoc (with-meta '*in*
|
||||
(when-not stream?
|
||||
{:sci/deref! true})) in)]
|
||||
(if (identical? ::EOF in)
|
||||
[nil 0] ;; done streaming
|
||||
(let [res [(let [res (eval-string expr ctx)]
|
||||
(when (some? res)
|
||||
(if-let [pr-f (cond shell-out println
|
||||
edn-out prn)]
|
||||
(if (coll? res)
|
||||
(doseq [l res
|
||||
:while (not (pipe-signal-received?))]
|
||||
(pr-f l))
|
||||
(pr-f res))
|
||||
(prn res)))) 0]]
|
||||
(if stream?
|
||||
(recur (read-next *in*))
|
||||
res)))))
|
||||
[(start-repl! ctx #(read-next *in*)) 0]))
|
||||
(catch Throwable e
|
||||
(binding [*out* *err*]
|
||||
(let [d (ex-data e)
|
||||
exit-code (:bb/exit-code d)]
|
||||
(if exit-code [nil exit-code]
|
||||
(do (if verbose?
|
||||
(print-stack-trace e)
|
||||
(println (.getMessage e)))
|
||||
(flush)
|
||||
[nil 1]))))))))
|
||||
1)
|
||||
;; handle preloads
|
||||
(if exit-code exit-code
|
||||
(do (when preloads (try (eval-string* sci-ctx preloads)
|
||||
(catch Throwable e
|
||||
(error-handler* e verbose?))))
|
||||
nil))
|
||||
exit-code
|
||||
(or exit-code
|
||||
(sci/with-bindings {reflection-var false}
|
||||
(or
|
||||
#_(binding [*out* *err*]
|
||||
(prn ">>" _opts))
|
||||
(second
|
||||
(cond version
|
||||
[(print-version) 0]
|
||||
help?
|
||||
[(print-help) 0]
|
||||
repl [(repl/start-repl! sci-ctx) 0]
|
||||
socket-repl [(start-socket-repl! socket-repl sci-ctx) 0]
|
||||
(not (str/blank? expression))
|
||||
(try
|
||||
(loop [in (read-next *in*)]
|
||||
(let [_ (swap! env update-in [:namespaces 'user]
|
||||
assoc (with-meta '*input*
|
||||
(when-not stream?
|
||||
{:sci.impl/deref! true}))
|
||||
(sci/new-dynamic-var '*input* in))]
|
||||
(if (identical? ::EOF in)
|
||||
[nil 0] ;; done streaming
|
||||
(let [res [(let [res (eval-string* sci-ctx expression)]
|
||||
(when (some? res)
|
||||
(if-let [pr-f (cond shell-out println
|
||||
edn-out prn)]
|
||||
(if (coll? res)
|
||||
(doseq [l res
|
||||
:while (not (pipe-signal-received?))]
|
||||
(pr-f l))
|
||||
(pr-f res))
|
||||
(prn res)))) 0]]
|
||||
(if stream?
|
||||
(recur (read-next *in*))
|
||||
res)))))
|
||||
(catch Throwable e
|
||||
(error-handler* e verbose?)))
|
||||
uberscript [nil 0]
|
||||
:else [(repl/start-repl! sci-ctx) 0]))
|
||||
1)))
|
||||
t1 (System/currentTimeMillis)]
|
||||
(flush)
|
||||
(when uberscript
|
||||
uberscript
|
||||
(let [uberscript-out uberscript]
|
||||
(spit uberscript-out "") ;; reset file
|
||||
(doseq [s @uberscript-sources]
|
||||
(spit uberscript-out s :append true))
|
||||
(spit uberscript-out preloads :append true)
|
||||
(spit uberscript-out expression :append true)))
|
||||
(when time? (binding [*out* *err*]
|
||||
(println "bb took" (str (- t1 t0) "ms."))))
|
||||
(flush)
|
||||
exit-code))
|
||||
|
||||
(defn -main
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
opts)
|
||||
t0 (System/currentTimeMillis)]
|
||||
(loop []
|
||||
(let [v (try (Socket. host port)
|
||||
(- (System/currentTimeMillis) t0)
|
||||
(let [v (try (with-open [_ (Socket. host port)]
|
||||
(- (System/currentTimeMillis) t0))
|
||||
(catch ConnectException _e
|
||||
(let [took (- (System/currentTimeMillis) t0)]
|
||||
(if (and timeout (>= took timeout))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
(ns ns-with-error)
|
||||
|
||||
(def x 0)
|
||||
(def y (/ 1 0))
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
(:require
|
||||
[babashka.test-utils :as tu]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.test :as t :refer [deftest is]]))
|
||||
[clojure.test :as t :refer [deftest is]]
|
||||
[clojure.java.io :as io]))
|
||||
|
||||
(defn bb [input & args]
|
||||
(edn/read-string (apply tu/bb (when (some? input) (str input)) (map str args))))
|
||||
|
|
@ -25,3 +26,26 @@
|
|||
(deftest main-test
|
||||
(is (= "(\"1\" \"2\" \"3\" \"4\")\n"
|
||||
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main" "1" "2" "3" "4"))))
|
||||
|
||||
(deftest uberscript-test
|
||||
(let [tmp-file (java.io.File/createTempFile "uberscript" ".clj")]
|
||||
(.deleteOnExit tmp-file)
|
||||
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test" "-m" "my.main" "--uberscript" (.getPath tmp-file))
|
||||
(is (= "(\"1\" \"2\" \"3\" \"4\")\n"
|
||||
(tu/bb nil "--file" (.getPath tmp-file) "1" "2" "3" "4")))))
|
||||
|
||||
(deftest error-while-loading-test
|
||||
(is (true?
|
||||
(bb nil "--classpath" "test-resources/babashka/src_for_classpath_test"
|
||||
"
|
||||
(try
|
||||
(require '[ns-with-error])
|
||||
(catch Exception nil))
|
||||
(nil? (resolve 'ns-with-error/x))"))))
|
||||
|
||||
(deftest resource-test
|
||||
(let [tmp-file (java.io.File/createTempFile "icon" ".png")]
|
||||
(.deleteOnExit tmp-file)
|
||||
(bb nil "--classpath" "logo" "-e" (format "(io/copy (io/input-stream (io/resource \"icon.png\")) (io/file \"%s\"))" (.getPath tmp-file)))
|
||||
(is (= (.length (io/file "logo" "icon.png"))
|
||||
(.length tmp-file)))))
|
||||
|
|
|
|||
17
test/babashka/file_var_test.clj
Normal file
17
test/babashka/file_var_test.clj
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(ns babashka.file-var-test
|
||||
(:require
|
||||
[babashka.test-utils :as tu]
|
||||
[clojure.test :as t :refer [deftest is]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn bb [input & args]
|
||||
(apply tu/bb (when (some? input) (str input)) (map str args)))
|
||||
|
||||
(deftest file-var-test
|
||||
(let [[f1 f2 f3]
|
||||
(str/split (bb nil "--classpath" "test/babashka/scripts"
|
||||
"test/babashka/scripts/file_var.bb")
|
||||
#"\n")]
|
||||
(is (str/ends-with? f1 "file_var_classpath.bb"))
|
||||
(is (str/ends-with? f2 "loaded_by_file_var.bb"))
|
||||
(is (str/ends-with? f3 "file_var.bb"))))
|
||||
21
test/babashka/http_connection_test.clj
Normal file
21
test/babashka/http_connection_test.clj
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
(ns babashka.http-connection-test
|
||||
(:require
|
||||
[babashka.test-utils :as tu]
|
||||
[clojure.test :as t :refer [deftest is]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn bb [& args]
|
||||
(apply tu/bb nil (map str args)))
|
||||
|
||||
(deftest open-connection-test
|
||||
(is (= "\"1\"" (str/trim (bb "-e" "
|
||||
(require '[cheshire.core :as json])
|
||||
(let [conn ^java.net.HttpURLConnection (.openConnection (java.net.URL. \"https://postman-echo.com/get?foo=1\"))]
|
||||
(.setConnectTimeout conn 1000)
|
||||
(.setRequestProperty conn \"Content-Type\" \"application/json\") ;; nonsensical, but to test if this method exists
|
||||
(.connect conn)
|
||||
(let [is (.getInputStream conn)
|
||||
err (.getErrorStream conn)
|
||||
response (json/decode (slurp is) true)]
|
||||
(-> response :args :foo)))
|
||||
")))))
|
||||
17
test/babashka/impl/clojure/java/shell_test.clj
Normal file
17
test/babashka/impl/clojure/java/shell_test.clj
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(ns babashka.impl.clojure.java.shell-test
|
||||
(:require [clojure.test :as t :refer [deftest is testing]]
|
||||
[babashka.test-utils :as test-utils]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(deftest with-sh-env-test
|
||||
(is (= "\"BAR\""
|
||||
(str/trim (test-utils/bb nil "
|
||||
(-> (shell/with-sh-env {:FOO \"BAR\"}
|
||||
(shell/sh \"bash\" \"-c\" \"echo $FOO\"))
|
||||
:out
|
||||
str/trim)"))))
|
||||
(is (str/includes? (str/trim (test-utils/bb nil "
|
||||
(-> (shell/with-sh-dir \"logo\"
|
||||
(shell/sh \"ls\"))
|
||||
:out)"))
|
||||
"icon.svg")))
|
||||
|
|
@ -2,32 +2,38 @@
|
|||
(:require
|
||||
[babashka.impl.repl :refer [start-repl!]]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :as t :refer [deftest is]]))
|
||||
[clojure.test :as t :refer [deftest is]]
|
||||
[sci.impl.opts :refer [init]]
|
||||
[sci.core :as sci]
|
||||
[sci.impl.vars :as vars]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
;; (vars/bindRoot sci/in *in*)
|
||||
;; (vars/bindRoot sci/out *out*)
|
||||
(vars/bindRoot sci/err *err*)
|
||||
|
||||
(defn repl! []
|
||||
(start-repl! {:bindings {(with-meta '*in*
|
||||
{:sci/deref! true})
|
||||
(delay [1 2 3])
|
||||
'*command-line-args*
|
||||
["a" "b" "c"]}
|
||||
:env (atom {})}))
|
||||
(start-repl! (init {:bindings {'*command-line-args*
|
||||
["a" "b" "c"]}
|
||||
:env (atom {})})))
|
||||
|
||||
(defn assert-repl [expr expected]
|
||||
(is (str/includes? (with-out-str
|
||||
(with-in-str (str expr "\n:repl/quit")
|
||||
(is (str/includes? (sci/with-out-str
|
||||
(sci/with-in-str (str expr "\n:repl/quit")
|
||||
(repl!))) expected)))
|
||||
|
||||
(deftest repl-test
|
||||
(assert-repl "1" "1")
|
||||
(assert-repl "[1 2 3]" "[1 2 3]")
|
||||
(assert-repl "()" "()")
|
||||
(assert-repl "(+ 1 2 3)" "6")
|
||||
(assert-repl "(defn foo [] (+ 1 2 3)) (foo)" "6")
|
||||
(assert-repl "(defn foo [] (+ 1 2 3)) (foo)" "6")
|
||||
(assert-repl "1\n(inc *1)" "2")
|
||||
(assert-repl "1\n(dec *1)(+ *2 *2)" "2")
|
||||
(assert-repl "1\n(dec *1)(+ *2 *2)" "2")
|
||||
(assert-repl "*command-line-args*" "[\"a\" \"b\" \"c\"]")
|
||||
(assert-repl "*in*" "[1 2 3]"))
|
||||
(assert-repl "*command-line-args*" "[\"a\" \"b\" \"c\"]"))
|
||||
|
||||
;;;; Scratch
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
[clojure.java.shell :refer [sh]]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :as t :refer [deftest is testing]]
|
||||
[clojure.java.io :as io]))
|
||||
[clojure.java.io :as io]
|
||||
[sci.impl.opts :refer [init]]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
|
|
@ -31,13 +32,10 @@
|
|||
(deftest socket-repl-test
|
||||
(try
|
||||
(if tu/jvm?
|
||||
(start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*in*
|
||||
{:sci/deref! true})
|
||||
(delay [1 2 3])
|
||||
'*command-line-args*
|
||||
["a" "b" "c"]}
|
||||
:env (atom {})
|
||||
:features #{:bb}})
|
||||
(start-repl! "0.0.0.0:1666" (init {:bindings {'*command-line-args*
|
||||
["a" "b" "c"]}
|
||||
:env (atom {})
|
||||
:features #{:bb}}))
|
||||
(future
|
||||
(sh "bash" "-c"
|
||||
"echo '[1 2 3]' | ./bb --socket-repl 0.0.0.0:1666 a b c")))
|
||||
|
|
@ -47,8 +45,6 @@
|
|||
(sh "bash" "-c"
|
||||
"lsof -t -i:1666"))))))
|
||||
(is (socket-command "(+ 1 2 3)" "user=> 6"))
|
||||
(testing "*in*"
|
||||
(is (socket-command "*in*" "[1 2 3]")))
|
||||
(testing "*command-line-args*"
|
||||
(is (socket-command '*command-line-args* "\"a\" \"b\" \"c\"")))
|
||||
(testing "&env"
|
||||
|
|
@ -72,7 +68,7 @@
|
|||
(dotimes [_ 1000]
|
||||
(t/run-tests))
|
||||
(stop-repl!)
|
||||
(start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*in*
|
||||
(start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*input*
|
||||
{:sci/deref! true})
|
||||
(delay [1 2 3])
|
||||
'*command-line-args*
|
||||
|
|
|
|||
19
test/babashka/java_time_test.clj
Normal file
19
test/babashka/java_time_test.clj
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
(ns babashka.java-time-test
|
||||
(:require
|
||||
[babashka.test-utils :as test-utils]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.test :as test :refer [deftest is]]))
|
||||
|
||||
(defn bb [expr]
|
||||
(edn/read-string (apply test-utils/bb nil [(str expr)])))
|
||||
|
||||
(deftest java-time-test
|
||||
(is (= "2019-12-18" (bb '(str (java.time.LocalDate/of 2019 12 18)))))
|
||||
(is (= "2019-12-01" (bb '(str
|
||||
(-> (java.time.LocalDate/of 2019 12 18)
|
||||
(.minusDays 17))))))
|
||||
(is (= "MONDAY" (bb '(str java.time.DayOfWeek/MONDAY))))
|
||||
(is (= "18-12-2019 16:01:41"
|
||||
(bb '(.format
|
||||
(java.time.LocalDateTime/parse "2019-12-18T16:01:41.485")
|
||||
(java.time.format.DateTimeFormatter/ofPattern "dd-MM-yyyy HH:mm:ss"))))))
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
[babashka.main :as main]
|
||||
[babashka.test-utils :as test-utils]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.java.shell :refer [sh]]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :as test :refer [deftest is testing]]
|
||||
[clojure.java.io :as io]
|
||||
[sci.core :as sci]))
|
||||
|
||||
(defn bb [input & args]
|
||||
|
|
@ -21,58 +21,58 @@
|
|||
|
||||
(testing "distinguish automatically between expression or file name"
|
||||
(is (= {:expression "(println 123)"
|
||||
:command-line-args []}
|
||||
:command-line-args nil}
|
||||
(main/parse-opts ["(println 123)"])))
|
||||
|
||||
(is (= {:file "src/babashka/main.clj"
|
||||
:command-line-args []}
|
||||
:command-line-args nil}
|
||||
(main/parse-opts ["src/babashka/main.clj"])))
|
||||
|
||||
(is (= {:expression "does-not-exist"
|
||||
:command-line-args []}
|
||||
:command-line-args nil}
|
||||
(main/parse-opts ["does-not-exist"])))))
|
||||
|
||||
(deftest main-test
|
||||
(testing "-io behaves as identity"
|
||||
(= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" "*in*")))
|
||||
(= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" "*input*")))
|
||||
(testing "if and when"
|
||||
(is (= 1 (bb 0 '(if (zero? *in*) 1 2))))
|
||||
(is (= 2 (bb 1 '(if (zero? *in*) 1 2))))
|
||||
(is (= 1 (bb 0 '(when (zero? *in*) 1))))
|
||||
(is (nil? (bb 1 '(when (zero? *in*) 1)))))
|
||||
(is (= 1 (bb 0 '(if (zero? *input*) 1 2))))
|
||||
(is (= 2 (bb 1 '(if (zero? *input*) 1 2))))
|
||||
(is (= 1 (bb 0 '(when (zero? *input*) 1))))
|
||||
(is (nil? (bb 1 '(when (zero? *input*) 1)))))
|
||||
(testing "and and or"
|
||||
(is (= false (bb 0 '(and false true *in*))))
|
||||
(is (= 0 (bb 0 '(and true true *in*))))
|
||||
(is (= 1 (bb 1 '(or false false *in*))))
|
||||
(is (= false (bb false '(or false false *in*))))
|
||||
(is (= 3 (bb false '(or false false *in* 3)))))
|
||||
(is (= false (bb 0 '(and false true *input*))))
|
||||
(is (= 0 (bb 0 '(and true true *input*))))
|
||||
(is (= 1 (bb 1 '(or false false *input*))))
|
||||
(is (= false (bb false '(or false false *input*))))
|
||||
(is (= 3 (bb false '(or false false *input* 3)))))
|
||||
(testing "fn"
|
||||
(is (= 2 (bb 1 "(#(+ 1 %) *in*)")))
|
||||
(is (= 2 (bb 1 "(#(+ 1 %) *input*)")))
|
||||
(is (= [1 2 3] (bb 1 "(map #(+ 1 %) [0 1 2])")))
|
||||
(is (= 1 (bb 1 "(#(when (odd? *in*) *in*))"))))
|
||||
(is (= 1 (bb 1 "(#(when (odd? *input*) *input*))"))))
|
||||
(testing "map"
|
||||
(is (= [1 2 3] (bb 1 '(map inc [0 1 2])))))
|
||||
(testing "keep"
|
||||
(is (= [false true false] (bb 1 '(keep odd? [0 1 2])))))
|
||||
(testing "->"
|
||||
(is (= 4 (bb 1 '(-> *in* inc inc (inc))))))
|
||||
(is (= 4 (bb 1 '(-> *input* inc inc (inc))))))
|
||||
(testing "->>"
|
||||
(is (= 10 (edn/read-string (test-utils/bb "foo\n\baar\baaaaz" "-i" "(->> *in* (map count) (apply max))")))))
|
||||
(is (= 10 (edn/read-string (test-utils/bb "foo\n\baar\baaaaz" "-i" "(->> *input* (map count) (apply max))")))))
|
||||
(testing "literals"
|
||||
(is (= {:a 4
|
||||
:b {:a 2}
|
||||
:c [1 1]
|
||||
:d #{1 2}}
|
||||
(bb 1 '{:a (+ 1 2 *in*)
|
||||
:b {:a (inc *in*)}
|
||||
:c [*in* *in*]
|
||||
:d #{*in* (inc *in*)}}))))
|
||||
(bb 1 '{:a (+ 1 2 *input*)
|
||||
:b {:a (inc *input*)}
|
||||
:c [*input* *input*]
|
||||
:d #{*input* (inc *input*)}}))))
|
||||
(testing "shuffle the contents of a file"
|
||||
(let [in "foo\n Clojure is nice. \nbar\n If you're nice to clojure. "
|
||||
in-lines (set (str/split in #"\n"))
|
||||
out (test-utils/bb in
|
||||
"-io"
|
||||
(str '(shuffle *in*)))
|
||||
(str '(shuffle *input*)))
|
||||
out-lines (set (str/split out #"\n"))]
|
||||
(is (= in-lines out-lines))))
|
||||
(testing "find occurrences in file by line number"
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
(->
|
||||
(bb "foo\n Clojure is nice. \nbar\n If you're nice to clojure. "
|
||||
"-i"
|
||||
"(map-indexed #(-> [%1 %2]) *in*)")
|
||||
(bb "(keep #(when (re-find #\"(?i)clojure\" (second %)) (first %)) *in*)"))))))
|
||||
"(map-indexed #(-> [%1 %2]) *input*)")
|
||||
(bb "(keep #(when (re-find #\"(?i)clojure\" (second %)) (first %)) *input*)"))))))
|
||||
|
||||
(deftest println-test
|
||||
(is (= "hello\n" (test-utils/bb nil "(println \"hello\")"))))
|
||||
|
||||
(deftest input-test
|
||||
(testing "bb doesn't wait for input if *in* isn't used"
|
||||
(testing "bb doesn't wait for input if *input* isn't used"
|
||||
(is (= "2\n" (with-out-str (main/main "(inc 1)"))))))
|
||||
|
||||
(deftest System-test
|
||||
|
|
@ -114,12 +114,12 @@
|
|||
(is (re-find #"doctype html" resp))))
|
||||
|
||||
(deftest stream-test
|
||||
(is (= "2\n3\n4\n" (test-utils/bb "1 2 3" "--stream" "(inc *in*)")))
|
||||
(is (= "2\n3\n4\n" (test-utils/bb "{:x 2} {:x 3} {:x 4}" "--stream" "(:x *in*)")))
|
||||
(is (= "2\n3\n4\n" (test-utils/bb "1 2 3" "--stream" "(inc *input*)")))
|
||||
(is (= "2\n3\n4\n" (test-utils/bb "{:x 2} {:x 3} {:x 4}" "--stream" "(:x *input*)")))
|
||||
(let [x "foo\n\bar\n"]
|
||||
(is (= x (test-utils/bb x "--stream" "-io" "*in*"))))
|
||||
(is (= x (test-utils/bb x "--stream" "-io" "*input*"))))
|
||||
(let [x "f\n\b\n"]
|
||||
(is (= x (test-utils/bb x "--stream" "-io" "(subs *in* 0 1)")))))
|
||||
(is (= x (test-utils/bb x "--stream" "-io" "(subs *input* 0 1)")))))
|
||||
|
||||
(deftest load-file-test
|
||||
(let [tmp (java.io.File/createTempFile "script" ".clj")]
|
||||
|
|
@ -145,29 +145,35 @@
|
|||
(deftest pipe-test
|
||||
(when test-utils/native?
|
||||
(let [out (:out (sh "bash" "-c" "./bb -o '(range)' |
|
||||
./bb --stream '(* *in* *in*)' |
|
||||
./bb --stream '(* *input* *input*)' |
|
||||
head -n10"))
|
||||
out (str/split-lines out)
|
||||
out (map edn/read-string out)]
|
||||
(is (= (take 10 (map #(* % %) (range))) out))))
|
||||
(when test-utils/native?
|
||||
(let [out (:out (sh "bash" "-c" "./bb -O '(repeat \"dude\")' |
|
||||
./bb --stream '(str *in* \"rino\")' |
|
||||
./bb -I '(take 3 *in*)'"))
|
||||
./bb --stream '(str *input* \"rino\")' |
|
||||
./bb -I '(take 3 *input*)'"))
|
||||
out (edn/read-string out)]
|
||||
(is (= '("duderino" "duderino" "duderino") out)))))
|
||||
|
||||
(deftest lazy-text-in-test
|
||||
(when test-utils/native?
|
||||
(let [out (:out (sh "bash" "-c" "yes | ./bb -i '(take 2 *in*)'"))
|
||||
(let [out (:out (sh "bash" "-c" "yes | ./bb -i '(take 2 *input*)'"))
|
||||
out (edn/read-string out)]
|
||||
(is (= '("y" "y") out)))))
|
||||
|
||||
(deftest future-test
|
||||
(is (= 6 (bb nil "@(future (+ 1 2 3))"))))
|
||||
|
||||
(deftest conch-test
|
||||
(is (str/includes? (bb nil "(->> (conch/proc \"ls\") (conch/stream-to-string :out))")
|
||||
(deftest process-builder-test
|
||||
(is (str/includes? (bb nil "
|
||||
(def ls (-> (ProcessBuilder. [\"ls\"]) (.start)))
|
||||
(def input (.getOutputStream ls))
|
||||
(.write (io/writer input) \"hello\") ;; dummy test just to see if this works
|
||||
(def output (.getInputStream ls))
|
||||
(assert (int? (.waitFor ls)))
|
||||
(slurp output)")
|
||||
"LICENSE")))
|
||||
|
||||
(deftest create-temp-file-test
|
||||
|
|
@ -181,11 +187,14 @@
|
|||
temp-dir-path))))))
|
||||
|
||||
(deftest wait-for-port-test
|
||||
(is (= :timed-out
|
||||
(bb nil "(def web-server (conch/proc \"python\" \"-m\" \"SimpleHTTPServer\" \"7171\"))
|
||||
(wait/wait-for-port \"127.0.0.1\" 7171)
|
||||
(conch/destroy web-server)
|
||||
(wait/wait-for-port \"localhost\" 7172 {:default :timed-out :timeout 50})"))))
|
||||
(let [server (test-utils/start-server! 1777)]
|
||||
(is (= 1777 (:port (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777)"))))
|
||||
(test-utils/stop-server! server)
|
||||
(is (= :timed-out (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777 {:default :timed-out :timeout 50})"))))
|
||||
(let [edn (bb nil (io/file "test" "babashka" "scripts" "socket_server.bb"))]
|
||||
(is (= "127.0.0.1" (:host edn)))
|
||||
(is (= 1777 (:port edn)))
|
||||
(is (number? (:took edn)))))
|
||||
|
||||
(deftest wait-for-path-test
|
||||
(let [temp-dir-path (System/getProperty "java.io.tmpdir")]
|
||||
|
|
@ -274,8 +283,8 @@
|
|||
f2 (.toFile p')]
|
||||
(bb nil (format
|
||||
"(let [f (io/file \"%s\")
|
||||
p (.toPath (io/file f))
|
||||
p' (.resolveSibling p \"f2\")]
|
||||
p (.toPath (io/file f))
|
||||
p' (.resolveSibling p \"f2\")]
|
||||
(.delete (.toFile p'))
|
||||
(dotimes [_ 2]
|
||||
(try
|
||||
|
|
@ -287,6 +296,48 @@
|
|||
|
||||
(deftest future-print-test
|
||||
(testing "the root binding of sci/*out*"
|
||||
(is (= "hello" (bb nil "@(future (prn \"hello\"))"))))
|
||||
(is (= "hello" (bb nil "@(future (prn \"hello\"))")))))
|
||||
|
||||
(deftest Math-test
|
||||
(is (== 8.0 (bb nil "(Math/pow 2 3)"))))
|
||||
|
||||
(deftest Base64-test
|
||||
(is (= "babashka"
|
||||
(bb nil "(String. (.decode (java.util.Base64/getDecoder) (.encode (java.util.Base64/getEncoder) (.getBytes \"babashka\"))))"))))
|
||||
|
||||
(deftest Thread-test
|
||||
(is (= "hello" (bb nil "(doto (java.lang.Thread. (fn [] (prn \"hello\"))) (.start) (.join)) nil"))))
|
||||
|
||||
(deftest dynvar-test
|
||||
(is (= 1 (bb nil "(binding [*command-line-args* 1] *command-line-args*)")))
|
||||
(is (= 1 (bb nil "(binding [*input* 1] *input*)"))))
|
||||
|
||||
(deftest file-in-error-msg-test
|
||||
(is (thrown-with-msg? Exception #"error.bb"
|
||||
(bb nil (.getPath (io/file "test" "babashka" "scripts" "error.bb"))))))
|
||||
|
||||
(deftest compatibility-test
|
||||
(is (true? (bb nil "(set! *warn-on-reflection* true)"))))
|
||||
|
||||
(deftest clojure-main-repl-test
|
||||
(is (= "\"> foo!\\nnil\\n> \"\n" (test-utils/bb nil "
|
||||
(defn foo [] (println \"foo!\"))
|
||||
(with-out-str
|
||||
(with-in-str \"(foo)\"
|
||||
(clojure.main/repl :init (fn []) :prompt (fn [] (print \"> \")))))"))))
|
||||
|
||||
(deftest command-line-args-test
|
||||
(is (true? (bb nil "(nil? *command-line-args*)")))
|
||||
(is (= ["1" "2" "3"] (bb nil "*command-line-args*" "1" "2" "3"))))
|
||||
|
||||
(deftest need-constructors-test
|
||||
(testing "the clojure.lang.Delay constructor works"
|
||||
(is (= 1 (bb nil "@(delay 1)"))))
|
||||
(testing "the clojure.lang.MapEntry constructor works"
|
||||
(is (true? (bb nil "(= (first {1 2}) (clojure.lang.MapEntry. 1 2))")))))
|
||||
|
||||
;;;; Scratch
|
||||
|
||||
(comment
|
||||
(dotimes [_ 10] (wait-for-port-test))
|
||||
)
|
||||
|
|
|
|||
1
test/babashka/scripts/error.bb
Normal file
1
test/babashka/scripts/error.bb
Normal file
|
|
@ -0,0 +1 @@
|
|||
(/ 1 0)
|
||||
6
test/babashka/scripts/file_var.bb
Normal file
6
test/babashka/scripts/file_var.bb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(ns file-var
|
||||
(:require [clojure.java.io :as io]))
|
||||
|
||||
(require '[file-var-classpath])
|
||||
(load-file (io/file "test" "babashka" "scripts" "loaded_by_file_var.bb"))
|
||||
(println *file*)
|
||||
1
test/babashka/scripts/file_var_classpath.bb
Normal file
1
test/babashka/scripts/file_var_classpath.bb
Normal file
|
|
@ -0,0 +1 @@
|
|||
(println *file*)
|
||||
3
test/babashka/scripts/loaded_by_file_var.bb
Normal file
3
test/babashka/scripts/loaded_by_file_var.bb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(ns loaded-by-file-var)
|
||||
|
||||
(println *file*)
|
||||
22
test/babashka/scripts/socket_server.bb
Normal file
22
test/babashka/scripts/socket_server.bb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(require '[babashka.wait :as wait])
|
||||
|
||||
(defn socket-loop [^java.net.ServerSocket server]
|
||||
(with-open [listener server]
|
||||
(loop []
|
||||
(with-open [socket (.accept listener)]
|
||||
(let [input-stream (.getInputStream socket)]
|
||||
(print (slurp input-stream))
|
||||
(flush)))
|
||||
(recur))))
|
||||
|
||||
(defn start-server! [port]
|
||||
(let [server (java.net.ServerSocket. port)]
|
||||
(future (socket-loop server))
|
||||
server))
|
||||
|
||||
(defn stop-server! [^java.net.ServerSocket server]
|
||||
(.close server))
|
||||
|
||||
(let [server (start-server! 1777)]
|
||||
(prn (wait/wait-for-port "127.0.0.1" 1777))
|
||||
(stop-server! server))
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
(:require
|
||||
[babashka.main :as main]
|
||||
[me.raynes.conch :refer [let-programs] :as sh]
|
||||
[sci.core :as sci]))
|
||||
[sci.core :as sci]
|
||||
[sci.impl.vars :as vars]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
|
|
@ -14,17 +15,25 @@
|
|||
bindings-map (cond-> {sci/out os
|
||||
sci/err es}
|
||||
is (assoc sci/in is))]
|
||||
(sci/with-bindings bindings-map
|
||||
(let [res (binding [*out* os
|
||||
*err* es]
|
||||
(if input
|
||||
(with-in-str input (apply main/main args))
|
||||
(apply main/main args)))]
|
||||
(if (zero? res)
|
||||
(str os)
|
||||
(throw (ex-info (str es)
|
||||
{:stdout (str os)
|
||||
:stderr (str es)})))))))
|
||||
(try
|
||||
(when input (vars/bindRoot sci/in is))
|
||||
(vars/bindRoot sci/out os)
|
||||
(vars/bindRoot sci/err es)
|
||||
(sci/with-bindings bindings-map
|
||||
(let [res (binding [*out* os
|
||||
*err* es]
|
||||
(if input
|
||||
(with-in-str input (apply main/main args))
|
||||
(apply main/main args)))]
|
||||
(if (zero? res)
|
||||
(str os)
|
||||
(throw (ex-info (str es)
|
||||
{:stdout (str os)
|
||||
:stderr (str es)})))))
|
||||
(finally
|
||||
(when input (vars/bindRoot sci/in *in*))
|
||||
(vars/bindRoot sci/out *out*)
|
||||
(vars/bindRoot sci/err *err*)))))
|
||||
|
||||
(defn bb-native [input & args]
|
||||
(let-programs [bb "./bb"]
|
||||
|
|
@ -49,3 +58,20 @@
|
|||
(if jvm?
|
||||
(println "==== Testing JVM version")
|
||||
(println "==== Testing native version"))
|
||||
|
||||
(defn socket-loop [^java.net.ServerSocket server]
|
||||
(with-open [listener server]
|
||||
(loop []
|
||||
(with-open [socket (.accept listener)]
|
||||
(let [input-stream (.getInputStream socket)]
|
||||
(print (slurp input-stream))
|
||||
(flush)))
|
||||
(recur))))
|
||||
|
||||
(defn start-server! [port]
|
||||
(let [server (java.net.ServerSocket. port)]
|
||||
(future (socket-loop server))
|
||||
server))
|
||||
|
||||
(defn stop-server! [^java.net.ServerSocket server]
|
||||
(.close server))
|
||||
|
|
|
|||
Loading…
Reference in a new issue