parent
c5d6768158
commit
a74be0ad1a
15 changed files with 470 additions and 60 deletions
|
|
@ -3,14 +3,16 @@
|
||||||
rm -rf /tmp/release
|
rm -rf /tmp/release
|
||||||
mkdir -p /tmp/release
|
mkdir -p /tmp/release
|
||||||
cp bb /tmp/release
|
cp bb /tmp/release
|
||||||
|
cp src-bash/bbk /tmp/release
|
||||||
|
|
||||||
VERSION=$(cat resources/BABASHKA_VERSION)
|
VERSION=$(cat resources/BABASHKA_VERSION)
|
||||||
|
|
||||||
cd /tmp/release
|
cd /tmp/release
|
||||||
|
|
||||||
## release binary as zip archive
|
## release binary as zip archive
|
||||||
|
|
||||||
zip "babashka-$VERSION-$BABASHKA_PLATFORM-amd64.zip" bb
|
zip "babashka-$VERSION-$BABASHKA_PLATFORM-amd64.zip" bb bbk
|
||||||
|
|
||||||
## cleanup
|
## cleanup
|
||||||
|
|
||||||
rm bb
|
rm bb bbk
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -13,3 +13,6 @@ pom.xml.asc
|
||||||
/bb
|
/bb
|
||||||
.clj-kondo/.cache
|
.clj-kondo/.cache
|
||||||
!java/src/babashka/impl/LockFix.class
|
!java/src/babashka/impl/LockFix.class
|
||||||
|
!test-resources/babashka/src_for_classpath_test/foo.jar
|
||||||
|
.cpcache
|
||||||
|
deps.edn
|
||||||
|
|
|
||||||
115
README.md
115
README.md
|
|
@ -311,6 +311,83 @@ $ cat script.clj
|
||||||
("hello" "1" "2" "3")
|
("hello" "1" "2" "3")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Preloads
|
||||||
|
|
||||||
|
The environment variable `BABASHKA_PRELOADS` allows to define code that will be
|
||||||
|
available in all subsequent usages of babashka.
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
BABASHKA_PRELOADS='(defn foo [x] (+ x 2))'
|
||||||
|
BABASHKA_PRELOADS=$BABASHKA_PRELOADS' (defn bar [x] (* x 2))'
|
||||||
|
export BABASHKA_PRELOADS
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that you can concatenate multiple expressions. Now you can use these functions in babashka:
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
$ bb '(-> (foo *in*) bar)' <<< 1
|
||||||
|
6
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also preload an entire file using `load-file`:
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
export BABASHKA_PRELOADS='(load-file "my_awesome_prelude.clj")'
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `*in*` is not available in preloads.
|
||||||
|
|
||||||
|
## Classpath
|
||||||
|
|
||||||
|
Babashka accepts a `--classpath` option that will be used to search for
|
||||||
|
namespaces and load them:
|
||||||
|
|
||||||
|
``` clojure
|
||||||
|
$ cat src/my/namespace.clj
|
||||||
|
(ns my.namespace)
|
||||||
|
(defn -main [& _args]
|
||||||
|
(println "Hello from my namespace!"))
|
||||||
|
|
||||||
|
$ bb --classpath src --main my.namespace
|
||||||
|
Hello from my namespace!
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that you can use the `clojure` tool to produce classpaths and download dependencies:
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
$ cat deps.edn
|
||||||
|
{:deps
|
||||||
|
{my_gist_script
|
||||||
|
{:git/url "https://gist.github.com/borkdude/263b150607f3ce03630e114611a4ef42"
|
||||||
|
:sha "cfc761d06dfb30bb77166b45d439fe8fe54a31b8"}}}
|
||||||
|
|
||||||
|
|
||||||
|
$ CLASSPATH=$(clojure -Spath)
|
||||||
|
$ bb --classpath "$CLASSPATH" --main my-gist-script
|
||||||
|
Hello from gist script!
|
||||||
|
```
|
||||||
|
|
||||||
|
The `bbk` shell script is a thin wrapper around the `clojure` tool, so you can
|
||||||
|
use Babashka projects in a similar way:
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
$ bbk -m my-gist-script
|
||||||
|
Hello from gist script!
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will call `bb` with the `--classpath` argument as a result of calling
|
||||||
|
`clojure`.
|
||||||
|
|
||||||
|
If there is no `--classpath` argument, the `BABASHKA_CLASSPATH` environment
|
||||||
|
variable will be used if set:
|
||||||
|
|
||||||
|
``` shellsession
|
||||||
|
$ export BABASHKA_CLASSPATH=$(clojure -Spath)
|
||||||
|
$ export BABASHKA_PRELOADS="(require '[my-gist-script])"
|
||||||
|
$ bb "(my-gist-script/-main)"
|
||||||
|
Hello from gist script!
|
||||||
|
```
|
||||||
|
|
||||||
## Parsing command line arguments
|
## Parsing command line arguments
|
||||||
|
|
||||||
Babashka ships with `clojure.tools.cli`:
|
Babashka ships with `clojure.tools.cli`:
|
||||||
|
|
@ -348,32 +425,6 @@ $ ./bb example.clj
|
||||||
babashka doesn't support in-ns yet!
|
babashka doesn't support in-ns yet!
|
||||||
```
|
```
|
||||||
|
|
||||||
## Preloads
|
|
||||||
|
|
||||||
The environment variable `BABASHKA_PRELOADS` allows to define code that will be
|
|
||||||
available in all subsequent usages of babashka.
|
|
||||||
|
|
||||||
``` shellsession
|
|
||||||
BABASHKA_PRELOADS='(defn foo [x] (+ x 2))'
|
|
||||||
BABASHKA_PRELOADS=$BABASHKA_PRELOADS' (defn bar [x] (* x 2))'
|
|
||||||
export BABASHKA_PRELOADS
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that you can concatenate multiple expressions. Now you can use these functions in babashka:
|
|
||||||
|
|
||||||
``` shellsession
|
|
||||||
$ bb '(-> (foo *in*) bar)' <<< 1
|
|
||||||
6
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also preload an entire file using `load-file`:
|
|
||||||
|
|
||||||
``` shellsession
|
|
||||||
export BABASHKA_PRELOADS='(load-file "my_awesome_prelude.clj")'
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that `*in*` is not available in preloads.
|
|
||||||
|
|
||||||
## Socket REPL
|
## Socket REPL
|
||||||
|
|
||||||
Start the socket REPL like this:
|
Start the socket REPL like this:
|
||||||
|
|
@ -448,16 +499,8 @@ Differences with Clojure:
|
||||||
|
|
||||||
- A subset of Java classes are supported.
|
- A subset of Java classes are supported.
|
||||||
|
|
||||||
- Only the `clojure.core`, `clojure.set` and `clojure.string` namespaces are
|
- Only the `clojure.core`, `clojure.set`, `clojure.string` and `clojure.walk`
|
||||||
available from Clojure.
|
namespaces are available from Clojure.
|
||||||
|
|
||||||
- There is no classpath and no support for loading code from Maven/Clojars
|
|
||||||
dependencies. However, you can use `load-file` to load external code from
|
|
||||||
disk.
|
|
||||||
|
|
||||||
- `require` does not load files; it only provides a way to create different
|
|
||||||
aliases for included namespaces, which makes it easier to make scripts
|
|
||||||
portable between the JVM and babashka.
|
|
||||||
|
|
||||||
- Interpretation comes with overhead. Therefore tight loops are likely slower
|
- Interpretation comes with overhead. Therefore tight loops are likely slower
|
||||||
than in Clojure on the JVM.
|
than in Clojure on the JVM.
|
||||||
|
|
|
||||||
2
sci
2
sci
|
|
@ -1 +1 @@
|
||||||
Subproject commit 60778bfaabf4fbed635d9490bac88b86fdfb0e4d
|
Subproject commit 968734ac60a2410f0b716df3829a5287f263e8f0
|
||||||
13
script/test
13
script/test
|
|
@ -1,6 +1,15 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
|
BABASHKA_PRELOADS=""
|
||||||
|
BABASHKA_CLASSPATH=""
|
||||||
|
lein test "$@"
|
||||||
|
|
||||||
lein test
|
BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
|
||||||
|
BABASHKA_PRELOADS_TEST=true
|
||||||
|
lein test :only babashka.main-test/preloads-test
|
||||||
|
|
||||||
|
BABASHKA_PRELOADS="(require '[env-ns])"
|
||||||
|
BABASHKA_CLASSPATH_TEST=true
|
||||||
|
BABASHKA_CLASSPATH="test-resources/babashka/src_for_classpath_test/env"
|
||||||
|
lein test :only babashka.classpath-test/classpath-env-test
|
||||||
|
|
|
||||||
219
src-bash/bbk
Executable file
219
src-bash/bbk
Executable file
|
|
@ -0,0 +1,219 @@
|
||||||
|
#!/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
|
||||||
62
src/babashka/impl/classpath.clj
Normal file
62
src/babashka/impl/classpath.clj
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
(ns babashka.impl.classpath
|
||||||
|
{:no-doc true}
|
||||||
|
(:require [clojure.java.io :as io]
|
||||||
|
[clojure.string :as str])
|
||||||
|
(:import [java.util.jar JarFile JarFile$JarFileEntry]))
|
||||||
|
|
||||||
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
(defprotocol IResourceResolver
|
||||||
|
(getResource [this path]))
|
||||||
|
|
||||||
|
(deftype DirectoryResolver [path]
|
||||||
|
IResourceResolver
|
||||||
|
(getResource [this resource-path]
|
||||||
|
(let [f (io/file path resource-path)]
|
||||||
|
(when (.exists f)
|
||||||
|
(slurp f)))))
|
||||||
|
|
||||||
|
(defn path-from-jar
|
||||||
|
[^java.io.File jar-file path]
|
||||||
|
(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)]
|
||||||
|
entry)))
|
||||||
|
|
||||||
|
(deftype JarFileResolver [path]
|
||||||
|
IResourceResolver
|
||||||
|
(getResource [this resource-path]
|
||||||
|
(path-from-jar path resource-path)))
|
||||||
|
|
||||||
|
(defn part->entry [part]
|
||||||
|
(if (str/ends-with? part ".jar")
|
||||||
|
(JarFileResolver. (io/file part))
|
||||||
|
(DirectoryResolver. (io/file part))))
|
||||||
|
|
||||||
|
(deftype Loader [entries]
|
||||||
|
IResourceResolver
|
||||||
|
(getResource [this resource-path]
|
||||||
|
(some #(getResource % resource-path) 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]
|
||||||
|
(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)))
|
||||||
|
|
||||||
|
;;;; 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)
|
||||||
|
)
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
[babashka.impl.socket-repl :as socket-repl]
|
[babashka.impl.socket-repl :as socket-repl]
|
||||||
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
||||||
[babashka.impl.utils :refer [eval-string]]
|
[babashka.impl.utils :refer [eval-string]]
|
||||||
|
[babashka.impl.classpath :as cp]
|
||||||
[babashka.wait :as wait]
|
[babashka.wait :as wait]
|
||||||
[clojure.edn :as edn]
|
[clojure.edn :as edn]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
|
|
@ -81,7 +82,15 @@
|
||||||
(let [options (rest options)]
|
(let [options (rest options)]
|
||||||
(recur (rest options)
|
(recur (rest options)
|
||||||
(assoc opts-map :expression (first options))))
|
(assoc opts-map :expression (first options))))
|
||||||
(if (some opts-map [:file :socket-repl :expression])
|
("--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
|
(assoc opts-map
|
||||||
:command-line-args options)
|
:command-line-args options)
|
||||||
(if (and (not= \( (first (str/trim opt)))
|
(if (and (not= \( (first (str/trim opt)))
|
||||||
|
|
@ -111,7 +120,10 @@
|
||||||
(defn print-version []
|
(defn print-version []
|
||||||
(println (str "babashka v"(str/trim (slurp (io/resource "BABASHKA_VERSION"))))))
|
(println (str "babashka v"(str/trim (slurp (io/resource "BABASHKA_VERSION"))))))
|
||||||
|
|
||||||
(def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [--verbose] [ --stream ] ( -e <expression> | -f <file> | --repl | --socket-repl [<host>:]<port> )")
|
(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> )
|
||||||
|
[ arg* ]")
|
||||||
(defn print-usage []
|
(defn print-usage []
|
||||||
(println usage-string))
|
(println usage-string))
|
||||||
|
|
||||||
|
|
@ -123,20 +135,21 @@
|
||||||
(println)
|
(println)
|
||||||
(println "Options:")
|
(println "Options:")
|
||||||
(println "
|
(println "
|
||||||
--help, -h or -?: print this help text.
|
--help, -h or -? Print this help text.
|
||||||
--version: print the current version of babashka.
|
--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 lines from stdin.
|
-I Bind *in* to a lazy seq of EDN values from stdin.
|
||||||
-I: bind *in* to a lazy seq of EDN values from stdin.
|
-o Write lines to stdout.
|
||||||
-o: write lines to stdout.
|
-O Write EDN values to stdout.
|
||||||
-O: write EDN values to stdout.
|
--verbose Print entire stacktrace in case of exception.
|
||||||
--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.
|
||||||
--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.
|
||||||
-e, --eval <expression>: evaluate an expression
|
-f, --file <path> Evaluate a file.
|
||||||
-f, --file <path>: evaluate a file
|
-cp, --classpath Classpath to use.
|
||||||
--repl: start REPL
|
-m, --main <ns> Call the -main function from namespace with args.
|
||||||
--socket-repl: start socket REPL. Specify port (e.g. 1666) or host and port separated by colon (e.g. 127.0.0.1:1666).
|
--repl Start REPL
|
||||||
--time: print execution time before exiting.
|
--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.
|
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*."))
|
Everything after that is bound to *command-line-args*."))
|
||||||
|
|
@ -193,7 +206,8 @@ Everything after that is bound to *command-line-args*."))
|
||||||
:help? :file :command-line-args
|
:help? :file :command-line-args
|
||||||
:expression :stream? :time?
|
:expression :stream? :time?
|
||||||
:repl :socket-repl
|
:repl :socket-repl
|
||||||
:verbose?] :as _opts}
|
:verbose? :classpath
|
||||||
|
:main] :as _opts}
|
||||||
(parse-opts args)
|
(parse-opts args)
|
||||||
read-next (fn [*in*]
|
read-next (fn [*in*]
|
||||||
(if (pipe-signal-received?)
|
(if (pipe-signal-received?)
|
||||||
|
|
@ -208,6 +222,13 @@ Everything after that is bound to *command-line-args*."))
|
||||||
:else
|
:else
|
||||||
(edn/read *in*))))))
|
(edn/read *in*))))))
|
||||||
env (atom {})
|
env (atom {})
|
||||||
|
classpath (or classpath
|
||||||
|
(System/getenv "BABASHKA_CLASSPATH"))
|
||||||
|
loader (when classpath
|
||||||
|
(cp/loader classpath))
|
||||||
|
load-fn (when classpath
|
||||||
|
(fn [{:keys [:namespace]}]
|
||||||
|
(cp/source-for-namespace loader namespace)))
|
||||||
ctx {:aliases '{tools.cli 'clojure.tools.cli
|
ctx {:aliases '{tools.cli 'clojure.tools.cli
|
||||||
edn clojure.edn
|
edn clojure.edn
|
||||||
wait babashka.wait
|
wait babashka.wait
|
||||||
|
|
@ -273,11 +294,16 @@ Everything after that is bound to *command-line-args*."))
|
||||||
File java.io.File
|
File java.io.File
|
||||||
String java.lang.String
|
String java.lang.String
|
||||||
System java.lang.System
|
System java.lang.System
|
||||||
Thread java.lang.Thread}}
|
Thread java.lang.Thread}
|
||||||
|
:load-fn load-fn}
|
||||||
ctx (update ctx :bindings assoc 'eval #(eval* ctx %)
|
ctx (update ctx :bindings assoc 'eval #(eval* ctx %)
|
||||||
'load-file #(load-file* ctx %))
|
'load-file #(load-file* ctx %))
|
||||||
ctx (addons/future ctx)
|
ctx (addons/future ctx)
|
||||||
_preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim) (eval-string 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)
|
||||||
exit-code
|
exit-code
|
||||||
(or
|
(or
|
||||||
#_(binding [*out* *err*]
|
#_(binding [*out* *err*]
|
||||||
|
|
|
||||||
4
test-resources/babashka/src_for_classpath_test/env/env_ns.clj
vendored
Normal file
4
test-resources/babashka/src_for_classpath_test/env/env_ns.clj
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
(ns env-ns)
|
||||||
|
|
||||||
|
(defn foo []
|
||||||
|
"env!")
|
||||||
BIN
test-resources/babashka/src_for_classpath_test/foo.jar
Normal file
BIN
test-resources/babashka/src_for_classpath_test/foo.jar
Normal file
Binary file not shown.
|
|
@ -0,0 +1,5 @@
|
||||||
|
(ns my.impl)
|
||||||
|
|
||||||
|
(defn impl-fn
|
||||||
|
"identity"
|
||||||
|
[x] x)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
(ns my.main
|
||||||
|
(:require [my.impl :as impl]))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(impl/impl-fn args))
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
(ns my-script)
|
||||||
|
|
||||||
|
(defn foo []
|
||||||
|
::bb)
|
||||||
27
test/babashka/classpath_test.clj
Normal file
27
test/babashka/classpath_test.clj
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
(ns babashka.classpath-test
|
||||||
|
(:require
|
||||||
|
[babashka.test-utils :as tu]
|
||||||
|
[clojure.edn :as edn]
|
||||||
|
[clojure.test :as t :refer [deftest is]]))
|
||||||
|
|
||||||
|
(defn bb [input & args]
|
||||||
|
(edn/read-string (apply tu/bb (when (some? input) (str input)) (map str args))))
|
||||||
|
|
||||||
|
(deftest classpath-test
|
||||||
|
(is (= :my-script/bb
|
||||||
|
(bb nil "--classpath" "test-resources/babashka/src_for_classpath_test"
|
||||||
|
"(require '[my-script :as ms]) (ms/foo)")))
|
||||||
|
(is (= "hello from foo\n"
|
||||||
|
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
|
||||||
|
"(require '[foo :as f]) (f/foo)"))))
|
||||||
|
|
||||||
|
(deftest classpath-env-test
|
||||||
|
;; for this test you have to set `BABASHKA_CLASSPATH` to test-resources/babashka/src_for_classpath_test/env
|
||||||
|
;; and `BABASHKA_PRELOADS` to "(require '[env-ns])"
|
||||||
|
(when (System/getenv "BABASHKA_CLASSPATH_TEST")
|
||||||
|
(println (System/getenv "BABASHKA_CLASSPATH"))
|
||||||
|
(is (= "env!" (bb nil "(env-ns/foo)")))))
|
||||||
|
|
||||||
|
(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"))))
|
||||||
|
|
@ -135,7 +135,8 @@
|
||||||
(deftest preloads-test
|
(deftest preloads-test
|
||||||
;; THIS TEST REQUIRES:
|
;; THIS TEST REQUIRES:
|
||||||
;; export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
|
;; export BABASHKA_PRELOADS='(defn __bb__foo [] "foo") (defn __bb__bar [] "bar")'
|
||||||
(is (= "foobar" (bb nil "(str (__bb__foo) (__bb__bar))"))))
|
(when (System/getenv "BABASHKA_PRELOADS_TEST")
|
||||||
|
(is (= "foobar" (bb nil "(str (__bb__foo) (__bb__bar))")))))
|
||||||
|
|
||||||
(deftest io-test
|
(deftest io-test
|
||||||
(is (true? (bb nil "(.exists (io/file \"README.md\"))")))
|
(is (true? (bb nil "(.exists (io/file \"README.md\"))")))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue