From 83b3aad92002d009f852e6beb6c75ccb91359b38 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 16 Dec 2019 21:44:20 +0100 Subject: [PATCH 001/169] [#158] Automate generation of reflection.json --- README.md | 4 + project.clj | 3 +- reflection.json | 399 ++++++++++++++++++---------------- reflection.json.bak | 185 ++++++++++++++++ src/babashka/impl/classes.clj | 118 ++++++++++ src/babashka/main.clj | 30 +-- 6 files changed, 525 insertions(+), 214 deletions(-) create mode 100644 reflection.json.bak create mode 100644 src/babashka/impl/classes.clj diff --git a/README.md b/README.md index 65771518..41656763 100644 --- a/README.md +++ b/README.md @@ -520,6 +520,10 @@ 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`. +### Generate reflection.json file + + lein with-profiles +reflection run + ### Test Test on the JVM (for development): diff --git a/project.clj b/project.clj index 4703e378..07cdfa04 100644 --- a/project.clj +++ b/project.clj @@ -21,7 +21,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 diff --git a/reflection.json b/reflection.json index a41c3fcd..63f3b320 100644 --- a/reflection.json +++ b/reflection.json @@ -1,185 +1,214 @@ -[ - { - "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" : "clojure.lang.ExceptionInfo", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "clojure.lang.LineNumberingPushbackReader", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.BufferedReader", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.BufferedWriter", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.File", + "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.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.lang.Class", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Double", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Exception", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Integer", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.String", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.System", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : 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.Path", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.StandardCopyOption", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : 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.util.regex.Pattern", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "sun.nio.fs.UnixPath", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "allPublicMethods" : true, + "name" : "java.util.concurrent.LinkedBlockingQueue" +}, { + "allPublicConstructors" : true, + "name" : "java.lang.Process" +}, { + "allPublicMethods" : true, + "name" : "java.lang.UNIXProcess" +}, { + "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" + } ], + "name" : "java.lang.Thread" +} ] \ No newline at end of file diff --git a/reflection.json.bak b/reflection.json.bak new file mode 100644 index 00000000..a41c3fcd --- /dev/null +++ b/reflection.json.bak @@ -0,0 +1,185 @@ +[ + { + "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 + } +] diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj new file mode 100644 index 00000000..16736baf --- /dev/null +++ b/src/babashka/impl/classes.clj @@ -0,0 +1,118 @@ +(ns babashka.impl.classes + {:no-doc true} + (:require + [cheshire.core :as json])) + +(def classes + {:default-classes '[java.lang.ArithmeticException + java.lang.AssertionError + java.lang.Boolean + java.io.BufferedWriter + java.io.BufferedReader + java.lang.Class + java.lang.Double + java.lang.Exception + clojure.lang.ExceptionInfo + java.lang.Integer + java.io.File + clojure.lang.LineNumberingPushbackReader + java.util.regex.Pattern + java.lang.String + java.io.StringReader + java.io.StringWriter + java.lang.System + sun.nio.fs.UnixPath + java.nio.file.attribute.FileAttribute + java.nio.file.attribute.PosixFilePermission + java.nio.file.attribute.PosixFilePermissions + java.nio.file.CopyOption + java.nio.file.FileAlreadyExistsException + java.nio.file.Files + java.nio.file.NoSuchFileException + java.nio.file.Path + java.nio.file.StandardCopyOption] + :custom-classes {'java.util.concurrent.LinkedBlockingQueue ;; why? + {:allPublicMethods true} + 'java.lang.Process ;; for conch? + {:allPublicConstructors true} + 'java.lang.UNIXProcess ;; for conch? + {:allPublicMethods true} + 'java.lang.Thread + ;; 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"}]}}}) + +(defmacro gen-class-map [] + (let [classes (concat (:default-classes classes) + (keys (:custom-classes classes)))] + (apply hash-map + (for [c classes + c [(list 'quote c) c]] + c)))) + +(def class-map (gen-class-map)) + +(defn generate-reflection-file + "Generate reflection.json file" + [& args] + (let [entries (vec (for [c (sort (:default-classes classes))] + {:name (str c) + :allPublicMethods true + :allPublicFields true + :allPublicConstructors true})) + custom-entries (for [[k v] (:custom-classes classes)] + (assoc v :name (str k))) + all-entries (concat entries 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.Thread) + ) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 392436b4..9e4f36c4 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -14,6 +14,7 @@ [babashka.impl.tools.cli :refer [tools-cli-namespace]] [babashka.impl.utils :refer [eval-string]] [babashka.impl.classpath :as cp] + [babashka.impl.classes :as classes] [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] @@ -256,34 +257,7 @@ Everything after that is bound to *command-line-args*.")) 'System/exit exit} :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 From c2d9bbfab28dad35c20cf1edebaee2b91fbc0eb1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 17 Dec 2019 11:27:40 +0100 Subject: [PATCH 002/169] [#160] Add support for ProcessBuilder (#165) --- README.md | 26 ++-- examples/process_builder.clj | 19 +++ reflection.json | 49 +++++-- sci | 2 +- src/babashka/impl/Boolean.clj | 15 --- src/babashka/impl/Double.clj | 15 --- src/babashka/impl/classes.clj | 60 +++++---- src/babashka/impl/conch.clj | 18 --- .../impl/me/raynes/conch/low_level.clj | 126 ------------------ src/babashka/main.clj | 8 +- test/babashka/main_test.clj | 16 ++- 11 files changed, 121 insertions(+), 233 deletions(-) create mode 100755 examples/process_builder.clj delete mode 100644 src/babashka/impl/Boolean.clj delete mode 100644 src/babashka/impl/Double.clj delete mode 100644 src/babashka/impl/conch.clj delete mode 100644 src/babashka/impl/me/raynes/conch/low_level.clj diff --git a/README.md b/README.md index 41656763..39eab12d 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,6 @@ enumerated explicitly. - [`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.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` @@ -191,6 +189,7 @@ The following Java classes are available: - `java.io.File` - `java.nio.Files` - `java.util.regex.Pattern` +- `ProcessBuilder` (see [example](examples/process_builder.clj)). - `String` - `System` - `Thread` @@ -446,22 +445,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 ' @@ -681,5 +685,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. diff --git a/examples/process_builder.clj b/examples/process_builder.clj new file mode 100755 index 00000000..0b064516 --- /dev/null +++ b/examples/process_builder.clj @@ -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") diff --git a/reflection.json b/reflection.json index 63f3b320..3af3a5fc 100644 --- a/reflection.json +++ b/reflection.json @@ -23,6 +23,16 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.io.InputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.OutputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.io.StringReader", "allPublicMethods" : true, @@ -68,6 +78,21 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.lang.Process", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.ProcessBuilder", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.ProcessBuilder$Redirect", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.lang.String", "allPublicMethods" : true, @@ -78,6 +103,16 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.lang.UNIXProcess", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.UNIXProcess$ProcessPipeOutputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.nio.file.CopyOption", "allPublicMethods" : true, @@ -123,6 +158,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.util.concurrent.LinkedBlockingQueue", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.util.regex.Pattern", "allPublicMethods" : true, @@ -133,15 +173,6 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true -}, { - "allPublicMethods" : true, - "name" : "java.util.concurrent.LinkedBlockingQueue" -}, { - "allPublicConstructors" : true, - "name" : "java.lang.Process" -}, { - "allPublicMethods" : true, - "name" : "java.lang.UNIXProcess" }, { "methods" : [ { "name" : "activeCount" diff --git a/sci b/sci index 07d28ee5..b86cb3db 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 07d28ee572e90a629e01b10aa5b98cb33ccdc1e5 +Subproject commit b86cb3db570ffcf6b193662481acceca25d3c979 diff --git a/src/babashka/impl/Boolean.clj b/src/babashka/impl/Boolean.clj deleted file mode 100644 index ee2e1853..00000000 --- a/src/babashka/impl/Boolean.clj +++ /dev/null @@ -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 - - ) diff --git a/src/babashka/impl/Double.clj b/src/babashka/impl/Double.clj deleted file mode 100644 index 50882b12..00000000 --- a/src/babashka/impl/Double.clj +++ /dev/null @@ -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 - - ) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 16736baf..e57a345e 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -4,40 +4,43 @@ [cheshire.core :as json])) (def classes - {:default-classes '[java.lang.ArithmeticException + {:default-classes '[clojure.lang.ExceptionInfo + clojure.lang.LineNumberingPushbackReader + java.io.BufferedReader + java.io.BufferedWriter + java.io.File + java.io.InputStream + java.io.OutputStream + java.io.StringReader + java.io.StringWriter + java.lang.ArithmeticException java.lang.AssertionError java.lang.Boolean - java.io.BufferedWriter - java.io.BufferedReader java.lang.Class java.lang.Double java.lang.Exception - clojure.lang.ExceptionInfo java.lang.Integer - java.io.File - clojure.lang.LineNumberingPushbackReader - java.util.regex.Pattern + java.util.concurrent.LinkedBlockingQueue java.lang.String - java.io.StringReader - java.io.StringWriter java.lang.System - sun.nio.fs.UnixPath - java.nio.file.attribute.FileAttribute - java.nio.file.attribute.PosixFilePermission - java.nio.file.attribute.PosixFilePermissions + java.lang.Process + java.lang.UNIXProcess + java.lang.UNIXProcess$ProcessPipeOutputStream + java.lang.ProcessBuilder + java.lang.ProcessBuilder$Redirect java.nio.file.CopyOption java.nio.file.FileAlreadyExistsException java.nio.file.Files java.nio.file.NoSuchFileException java.nio.file.Path - java.nio.file.StandardCopyOption] - :custom-classes {'java.util.concurrent.LinkedBlockingQueue ;; why? - {:allPublicMethods true} - 'java.lang.Process ;; for conch? - {:allPublicConstructors true} - 'java.lang.UNIXProcess ;; for conch? - {:allPublicMethods true} - 'java.lang.Thread + java.nio.file.StandardCopyOption + java.nio.file.attribute.FileAttribute + java.nio.file.attribute.PosixFilePermission + java.nio.file.attribute.PosixFilePermissions + java.util.regex.Pattern + sun.nio.fs.UnixPath ;; included because of permission check + ] + :custom-classes {'java.lang.Thread ;; generated with `public-declared-method-names`, see in ;; `comment` below {:methods [{:name "activeCount"} @@ -84,16 +87,21 @@ (def class-map (gen-class-map)) +#_(defn sym->class-name [sym] + (-> sym str (str/replace "$" "."))) + (defn generate-reflection-file "Generate reflection.json file" [& args] - (let [entries (vec (for [c (sort (:default-classes classes))] - {:name (str c) + (let [entries (vec (for [c (sort (:default-classes classes)) + :let [class-name (str c)]] + {:name class-name :allPublicMethods true :allPublicFields true :allPublicConstructors true})) - custom-entries (for [[k v] (:custom-classes classes)] - (assoc v :name (str k))) + custom-entries (for [[c v] (:custom-classes classes) + :let [class-name (str c)]] + (assoc v :name class-name)) all-entries (concat entries custom-entries)] (spit (or (first args) @@ -114,5 +122,5 @@ (sort-by :name) (vec))) - (public-declared-method-names java.lang.Thread) + (public-declared-method-names java.lang.UNIXProcess) ) diff --git a/src/babashka/impl/conch.clj b/src/babashka/impl/conch.clj deleted file mode 100644 index e53e8a99..00000000 --- a/src/babashka/impl/conch.clj +++ /dev/null @@ -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}) diff --git a/src/babashka/impl/me/raynes/conch/low_level.clj b/src/babashka/impl/me/raynes/conch/low_level.clj deleted file mode 100644 index 0de31bdc..00000000 --- a/src/babashka/impl/me/raynes/conch/low_level.clj +++ /dev/null @@ -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))) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 9e4f36c4..454c7309 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -3,18 +3,17 @@ (: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.csv :as csv] [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.classes :as classes] [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] @@ -236,7 +235,6 @@ Everything after that is bound to *command-line-args*.")) 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} @@ -249,7 +247,6 @@ Everything after that is bound to *command-line-args*.")) '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} @@ -266,6 +263,7 @@ Everything after that is bound to *command-line-args*.")) Exception java.lang.Exception Integer java.lang.Integer File java.io.File + ProcessBuilder java.lang.ProcessBuilder String java.lang.String System java.lang.System Thread java.lang.Thread} diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index e1f2a224..2352645a 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -166,8 +166,12 @@ (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 output (.getInputStream ls)) +(.waitFor ls) +(slurp output)") "LICENSE"))) (deftest create-temp-file-test @@ -182,10 +186,10 @@ (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})")))) + (bb nil "(def ws (-> (ProcessBuilder. [\"python\" \"-m\" \"SimpleHTTPServer\" \"1777\"]) (.start))) + (wait/wait-for-port \"127.0.0.1\" 1777) + (.destroy ws) + (wait/wait-for-port \"localhost\" 1777 {:default :timed-out :timeout 50})")))) (deftest wait-for-path-test (let [temp-dir-path (System/getProperty "java.io.tmpdir")] From aa8e6b160b6bed4dd385d86069325afceaaa8e5d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 17 Dec 2019 12:23:34 +0100 Subject: [PATCH 003/169] Close socket --- src/babashka/wait.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/babashka/wait.clj b/src/babashka/wait.clj index dbf54d2b..af2cc9d4 100644 --- a/src/babashka/wait.clj +++ b/src/babashka/wait.clj @@ -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)) From 16129a8db10c65c05d1bd725159542564d69bbb2 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Tue, 17 Dec 2019 15:35:03 +0100 Subject: [PATCH 004/169] Add project.clj->deps.edn oneliner to gallery --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 39eab12d..6a0ed4bf 100644 --- a/README.md +++ b/README.md @@ -673,6 +673,12 @@ 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 + +``` +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 *in*))] {:paths (into source-paths resource-paths) :deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))} ) ' | jet --pretty > deps.edn +``` + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support From c7a00f2c159a7788012c9d27514ccaad815c3e95 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 17 Dec 2019 15:37:05 +0100 Subject: [PATCH 005/169] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a0ed4bf..47489e52 100644 --- a/README.md +++ b/README.md @@ -675,8 +675,13 @@ cheshire/cheshire can be upgraded from 5.8.1 to 5.9.0 ### Convert project.clj to deps.edn -``` -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 *in*))] {:paths (into source-paths resource-paths) :deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))} ) ' | jet --pretty > deps.edn +``` 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 *in*))] + {:paths (into source-paths resource-paths) + :deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))}) ' | +jet --pretty > deps.edn ``` ## Thanks From a53cf43c0c124fe449d3e66cad934a085908749a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 08:51:40 +0100 Subject: [PATCH 006/169] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 47489e52..791e9003 100644 --- a/README.md +++ b/README.md @@ -675,6 +675,8 @@ 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' | From 36c3a637f67b7ab786fa0141f1cc72a08812105b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 08:52:14 +0100 Subject: [PATCH 007/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 791e9003..7df55cac 100644 --- a/README.md +++ b/README.md @@ -675,7 +675,7 @@ 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) +Contributed by [@plexus](https://github.com/plexus). ``` shellsession $ cat project.clj | From 96b04b50ef72a964b2ebc42c4f26aec9c0ee8e35 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 08:53:32 +0100 Subject: [PATCH 008/169] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7df55cac..44146a16 100644 --- a/README.md +++ b/README.md @@ -625,6 +625,8 @@ bb '(some #(re-find #".*linux.*" (:browser_download_url %)) *in*)' ### 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))' | From d88c28ff500c6804dd4df4b85b5ee7a44756f504 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 09:38:45 +0100 Subject: [PATCH 009/169] Fix flaky wait for test --- test/babashka/main_test.clj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 2352645a..4adf1ba7 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -7,7 +7,8 @@ [clojure.string :as str] [clojure.test :as test :refer [deftest is testing]] [clojure.java.io :as io] - [sci.core :as sci])) + [sci.core :as sci] + [clojure.test :as t])) (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) @@ -189,6 +190,7 @@ (bb nil "(def ws (-> (ProcessBuilder. [\"python\" \"-m\" \"SimpleHTTPServer\" \"1777\"]) (.start))) (wait/wait-for-port \"127.0.0.1\" 1777) (.destroy ws) + (.waitFor ws) (wait/wait-for-port \"localhost\" 1777 {:default :timed-out :timeout 50})")))) (deftest wait-for-path-test @@ -291,6 +293,10 @@ (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\"))"))))) +;;;; Scratch + +(comment + (dotimes [i 10] (wait-for-port-test)) ) From 316cce2b594490e58610e1c08823e4a01030d8e7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 13:46:07 +0100 Subject: [PATCH 010/169] Add java.lang.Math --- README.md | 1 + reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + src/babashka/main.clj | 1 + test/babashka/main_test.clj | 3 +++ 5 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 44146a16..b2789187 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ The following Java classes are available: - `Exception` - `clojure.lang.ExceptionInfo` - `Integer` +- `Math` - `java.io.File` - `java.nio.Files` - `java.util.regex.Pattern` diff --git a/reflection.json b/reflection.json index 3af3a5fc..030baf63 100644 --- a/reflection.json +++ b/reflection.json @@ -78,6 +78,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.lang.Math", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.lang.Process", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index e57a345e..d4938344 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -20,6 +20,7 @@ java.lang.Double java.lang.Exception java.lang.Integer + java.lang.Math java.util.concurrent.LinkedBlockingQueue java.lang.String java.lang.System diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 454c7309..8427a01b 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -263,6 +263,7 @@ Everything after that is bound to *command-line-args*.")) Exception java.lang.Exception Integer java.lang.Integer File java.io.File + Math java.lang.Math ProcessBuilder java.lang.ProcessBuilder String java.lang.String System java.lang.System diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 4adf1ba7..7fa304ad 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -295,6 +295,9 @@ (testing "the root binding of sci/*out*" (is (= "hello" (bb nil "@(future (prn \"hello\"))"))))) +(deftest Math-test + (is (== 8.0 (bb nil "(Math/pow 2 3)")))) + ;;;; Scratch (comment From 1b1e564288d4ab4f0777a0aed1349cf3c9c7bc1c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 16:38:21 +0100 Subject: [PATCH 011/169] [#149] Add java.time.* classes --- README.md | 4 ++ examples/pst.clj | 7 +++ reflection.json | 100 +++++++++++++++++++++++++++++++ src/babashka/impl/classes.clj | 20 +++++++ test/babashka/java_time_test.clj | 19 ++++++ test/babashka/main_test.clj | 5 +- 6 files changed, 152 insertions(+), 3 deletions(-) create mode 100755 examples/pst.clj create mode 100644 test/babashka/java_time_test.clj diff --git a/README.md b/README.md index b2789187..7146c83c 100644 --- a/README.md +++ b/README.md @@ -689,6 +689,10 @@ bb '(let [{:keys [dependencies source-paths resource-paths]} (apply hash-map (dr jet --pretty > deps.edn ``` +### Print current time in California + +See [examples/pst.clj](https://github.com/borkdude/babashka/blob/master/examples/pst.clj) + ## Thanks - [adgoji](https://www.adgoji.com/) for financial support diff --git a/examples/pst.clj b/examples/pst.clj new file mode 100755 index 00000000..2a919f5f --- /dev/null +++ b/examples/pst.clj @@ -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)) diff --git a/reflection.json b/reflection.json index 030baf63..507ad76c 100644 --- a/reflection.json +++ b/reflection.json @@ -163,6 +163,106 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.time.Clock", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.DateTimeException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.DayOfWeek", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.Duration", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.Instant", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.LocalDate", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.LocalDateTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.LocalTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.Month", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.MonthDay", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.OffsetDateTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.OffsetTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.Period", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.Year", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.YearMonth", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.ZoneId", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.ZoneOffset", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.ZonedDateTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.format.DateTimeFormatter", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.time.temporal.TemporalAccessor", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.util.concurrent.LinkedBlockingQueue", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index d4938344..be6cbec9 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -38,6 +38,26 @@ java.nio.file.attribute.FileAttribute 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 sun.nio.fs.UnixPath ;; included because of permission check ] diff --git a/test/babashka/java_time_test.clj b/test/babashka/java_time_test.clj new file mode 100644 index 00000000..65b22709 --- /dev/null +++ b/test/babashka/java_time_test.clj @@ -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")))))) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 7fa304ad..056246a0 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -3,12 +3,11 @@ [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] - [clojure.test :as t])) + [sci.core :as sci])) (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) From f8a19d2f4673e3f073050a0376fc4c387933adc9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 17:01:00 +0100 Subject: [PATCH 012/169] [#162] add java.util.Base64 --- reflection.json | 15 +++++++++++++++ src/babashka/impl/classes.clj | 3 +++ test/babashka/main_test.clj | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/reflection.json b/reflection.json index 507ad76c..ee23dd4c 100644 --- a/reflection.json +++ b/reflection.json @@ -263,6 +263,21 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.util.Base64", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.Base64$Decoder", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.Base64$Encoder", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.util.concurrent.LinkedBlockingQueue", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index be6cbec9..36965fc3 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -59,6 +59,9 @@ java.time.ZoneOffset java.time.temporal.TemporalAccessor java.util.regex.Pattern + java.util.Base64 + java.util.Base64$Decoder + java.util.Base64$Encoder sun.nio.fs.UnixPath ;; included because of permission check ] :custom-classes {'java.lang.Thread diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 056246a0..81affbd8 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -297,6 +297,10 @@ (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\"))))")))) + ;;;; Scratch (comment From 3bcd4f1742a7467f0dd7e5d47de656239d4db33f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 17:01:21 +0100 Subject: [PATCH 013/169] doc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7146c83c..cd09bf47 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ The following Java classes are available: - `Math` - `java.io.File` - `java.nio.Files` +- `java.util.Base64` - `java.util.regex.Pattern` - `ProcessBuilder` (see [example](examples/process_builder.clj)). - `String` From 51c2c42853e46cf33decf5c4d347ca4a4d72189a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 17:10:23 +0100 Subject: [PATCH 014/169] v0.0.43 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 382bf853..5c49468d 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.43-SNAPSHOT +0.0.43 From f205fea4473a549c4c73627d1763a6159f47777b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 17:15:45 +0100 Subject: [PATCH 015/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 54a00221..5c49468d 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.42 +0.0.43 diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 5c49468d..dfafd65e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.43 +0.0.44-SNAPSHOT From 58568c0b7ad7fee23ad02d95ac42d0d025fcb56e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 21:46:35 +0100 Subject: [PATCH 016/169] sci: letfn --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index b86cb3db..95cad890 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit b86cb3db570ffcf6b193662481acceca25d3c979 +Subproject commit 95cad890b5112448a732067b34e90b1935b6193a From 59748a5ce093a27f1d441f994c1dca2f53dffbb9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 18 Dec 2019 23:06:51 +0100 Subject: [PATCH 017/169] [#166] unit test: wait/wait-for-port closes connection --- test/babashka/main_test.clj | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 81affbd8..ae9af243 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -190,7 +190,14 @@ (wait/wait-for-port \"127.0.0.1\" 1777) (.destroy ws) (.waitFor ws) - (wait/wait-for-port \"localhost\" 1777 {:default :timed-out :timeout 50})")))) + (wait/wait-for-port \"localhost\" 1777 {:default :timed-out :timeout 50})"))) + (is (int? (bb nil " +(require '[babashka.wait :as wait]) +(def ws (-> (ProcessBuilder. [\"python\" \"-m\" \"SimpleHTTPServer\" \"1777\"]) (.start))) +(wait/wait-for-port \"localhost\" 1777) +(slurp \"http://localhost:1777\") +(.destroy ws) +(.waitFor ws)")))) (deftest wait-for-path-test (let [temp-dir-path (System/getProperty "java.io.tmpdir")] From d1d2db040bd4473f265aa7ba4c4ad853396f3cff Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 14:00:46 +0100 Subject: [PATCH 018/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd09bf47..5ae667c2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) -[![cljdoc badge](https://cljdoc.org/badge/borkdude/babashka)](https://cljdoc.org/d/borkdude/babashka/CURRENT) + [![project chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://app.slack.com/client/T03RZGPFR/CLX41ASCS) From 6ab9ff9b1564d9baab0df926e95f28991a1014a5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 14:01:14 +0100 Subject: [PATCH 019/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ae667c2..dc8a0667 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) - [![project chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://app.slack.com/client/T03RZGPFR/CLX41ASCS) + A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash. From 725f2174d18eca155e7fe26a751183d6e02b6d54 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 14:02:44 +0100 Subject: [PATCH 020/169] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3a14c403..08efe995 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -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** From 5e10c913e0dc706c4b4de85e508779a67c6e51c0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 18:26:17 +0100 Subject: [PATCH 021/169] [#174] Add edn/read --- src/babashka/main.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 8427a01b..184aaff2 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -241,7 +241,8 @@ Everything after that is bound to *command-line-args*.")) :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.edn {'read edn/read + '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} From a9231b7ecf3e1489d940ce2d32a45ccfe7ce14bf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 21:41:57 +0100 Subject: [PATCH 022/169] [#173] rename *in* to (BREAKING!) --- README.md | 44 +++++++++--------- src/babashka/main.clj | 12 ++--- test/babashka/impl/repl_test.clj | 4 +- test/babashka/impl/socket_repl_test.clj | 8 ++-- test/babashka/main_test.clj | 60 ++++++++++++------------- 5 files changed, 64 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index dc8a0667..348721a2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas ``` 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) )' ("doc" "resources" "sci" "script" "src" "target" "test") bb took 4ms. ``` @@ -57,29 +57,29 @@ Experimental. Breaking changes are expected to happen at this phase. ## Examples ``` shellsession -$ ls | bb -i '*in*' +$ ls | bb -i '' ["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"] -$ ls | bb -i '(count *in*)' +$ ls | bb -i '(count )' 12 -$ bb '(vec (dedupe *in*))' <<< '[1 1 1 1 2]' +$ bb '(vec (dedupe ))' <<< '[1 1 1 1 2]' [1 2] -$ bb '(filterv :foo *in*)' <<< '[{:foo 1} {:bar 2}]' +$ bb '(filterv :foo )' <<< '[{:foo 1} {:bar 2}]' [{:foo 1}] -$ bb '(#(+ %1 %2 %3) 1 2 *in*)' <<< 3 +$ bb '(#(+ %1 %2 %3) 1 2 )' <<< 3 6 -$ ls | bb -i '(filterv #(re-find #"reflection" %) *in*)' +$ ls | bb -i '(filterv #(re-find #"reflection" %) )' ["reflection.json"] $ bb '(run! #(shell/sh "touch" (str "/tmp/test/" %)) (range 100))' -$ ls /tmp/test | bb -i '*in*' +$ ls /tmp/test | bb -i '' ["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 "rino")' | bb -I '(take 3 )' ("duderino" "duderino" "duderino") ``` @@ -136,12 +136,12 @@ 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. + -i Bind to a lazy seq of lines from stdin. + -I Bind 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. + --stream Stream over lines or EDN values from stdin. Combined with -i or -I becomes a single value per iteration. -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. @@ -214,7 +214,7 @@ conditionals](#reader-conditionals) to maintain compatibility with JVM Clojure. Special vars: -- `*in*`: contains the input read from stdin. EDN by default, multiple lines of +- ``: 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 @@ -330,7 +330,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 ) bar)' <<< 1 6 ``` @@ -340,7 +340,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 `` is not available in preloads. ## Classpath @@ -563,7 +563,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 ] (.delete (io/file f)))' ``` ### Calculate aggregate size of directory @@ -597,7 +597,7 @@ $ cat /tmp/test.txt 3 Babashka 4 Goodbye -$ < /tmp/test.txt bb -io '(shuffle *in*)' +$ < /tmp/test.txt bb -io '(shuffle )' 3 Babashka 2 Clojure 4 Goodbye @@ -611,7 +611,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 '(-> first :name (subs 1))' "0.0.4" ``` @@ -620,8 +620,8 @@ 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 '(-> first :assets)' | +bb '(some #(re-find #".*linux.*" (:browser_download_url %)) )' "https://github.com/borkdude/babashka/releases/download/v0.0.4/babashka-0.0.4-linux-amd64.zip" ``` @@ -631,7 +631,7 @@ 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] ] (str (reduce + (vals counts)) " " group "/" art))' | sort -rn | less 14113842 clojure-complete/clojure-complete @@ -684,7 +684,7 @@ 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 *in*))] +bb '(let [{:keys [dependencies source-paths resource-paths]} (apply hash-map (drop 3 ))] {:paths (into source-paths resource-paths) :deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))}) ' | jet --pretty > deps.edn diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 184aaff2..69c50b8e 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -137,12 +137,12 @@ (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. + -i Bind to a lazy seq of lines from stdin. + -I Bind 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. + --stream Stream over lines or EDN values from stdin. Combined with -i or -I becomes a single value per iteration. -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. @@ -175,14 +175,14 @@ Everything after that is bound to *command-line-args*.")) (defn start-repl! [ctx read-next] (let [ctx (update ctx :bindings assoc - (with-meta '*in* + (with-meta ' {:sci/deref! true}) (read-next))] (repl/start-repl! ctx))) (defn start-socket-repl! [address ctx read-next] (let [ctx (update ctx :bindings assoc - (with-meta '*in* + (with-meta ' {:sci/deref! true}) (read-next))] (socket-repl/start-repl! address ctx) @@ -294,7 +294,7 @@ Everything after that is bound to *command-line-args*.")) (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* + (let [ctx (update-in ctx [:namespaces 'user] assoc (with-meta ' (when-not stream? {:sci/deref! true})) in)] (if (identical? ::EOF in) diff --git a/test/babashka/impl/repl_test.clj b/test/babashka/impl/repl_test.clj index 8adbde77..dfe49c74 100644 --- a/test/babashka/impl/repl_test.clj +++ b/test/babashka/impl/repl_test.clj @@ -7,7 +7,7 @@ (set! *warn-on-reflection* true) (defn repl! [] - (start-repl! {:bindings {(with-meta '*in* + (start-repl! {:bindings {(with-meta ' {:sci/deref! true}) (delay [1 2 3]) '*command-line-args* @@ -27,7 +27,7 @@ (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 "" "[1 2 3]")) ;;;; Scratch diff --git a/test/babashka/impl/socket_repl_test.clj b/test/babashka/impl/socket_repl_test.clj index 085561dd..ad04df74 100644 --- a/test/babashka/impl/socket_repl_test.clj +++ b/test/babashka/impl/socket_repl_test.clj @@ -31,7 +31,7 @@ (deftest socket-repl-test (try (if tu/jvm? - (start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*in* + (start-repl! "0.0.0.0:1666" {:bindings {(with-meta ' {:sci/deref! true}) (delay [1 2 3]) '*command-line-args* @@ -47,8 +47,8 @@ (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 "" + (is (socket-command "" "[1 2 3]"))) (testing "*command-line-args*" (is (socket-command '*command-line-args* "\"a\" \"b\" \"c\""))) (testing "&env" @@ -72,7 +72,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 ' {:sci/deref! true}) (delay [1 2 3]) '*command-line-args* diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index ae9af243..492bd252 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -34,45 +34,45 @@ (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" ""))) (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? ) 1 2)))) + (is (= 2 (bb 1 '(if (zero? ) 1 2)))) + (is (= 1 (bb 0 '(when (zero? ) 1)))) + (is (nil? (bb 1 '(when (zero? ) 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 )))) + (is (= 0 (bb 0 '(and true true )))) + (is (= 1 (bb 1 '(or false false )))) + (is (= false (bb false '(or false false )))) + (is (= 3 (bb false '(or false false 3))))) (testing "fn" - (is (= 2 (bb 1 "(#(+ 1 %) *in*)"))) + (is (= 2 (bb 1 "(#(+ 1 %) )"))) (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? ) ))")))) (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 '(-> 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" "(->> (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 ) + :b {:a (inc )} + :c [ ] + :d #{ (inc )}})))) (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 ))) 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]) )") + (bb "(keep #(when (re-find #\"(?i)clojure\" (second %)) (first %)) )")))))) (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 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 )"))) + (is (= "2\n3\n4\n" (test-utils/bb "{:x 2} {:x 3} {:x 4}" "--stream" "(:x )"))) (let [x "foo\n\bar\n"] - (is (= x (test-utils/bb x "--stream" "-io" "*in*")))) + (is (= x (test-utils/bb x "--stream" "-io" "")))) (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 0 1)"))))) (deftest load-file-test (let [tmp (java.io.File/createTempFile "script" ".clj")] @@ -145,21 +145,21 @@ (deftest pipe-test (when test-utils/native? (let [out (:out (sh "bash" "-c" "./bb -o '(range)' | - ./bb --stream '(* *in* *in*)' | + ./bb --stream '(* )' | 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 \"rino\")' | + ./bb -I '(take 3 )'")) 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 )'")) out (edn/read-string out)] (is (= '("y" "y") out))))) From 4f488ca684b47787a67ffc91130610bae4e73d28 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 23:34:27 +0100 Subject: [PATCH 023/169] [#159] set sci var roots to *in*, *out* and *err* --- reflection.json | 1 + src/babashka/impl/classes.clj | 7 ++++--- src/babashka/impl/utils.clj | 13 ++++++++----- test/babashka/main_test.clj | 5 ++++- test/babashka/test_utils.clj | 33 +++++++++++++++++++++------------ 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/reflection.json b/reflection.json index ee23dd4c..e010ef02 100644 --- a/reflection.json +++ b/reflection.json @@ -294,6 +294,7 @@ "allPublicFields" : true, "allPublicConstructors" : true }, { + "allPublicConstructors" : true, "methods" : [ { "name" : "activeCount" }, { diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 36965fc3..987197f2 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -65,9 +65,10 @@ sun.nio.fs.UnixPath ;; included because of permission check ] :custom-classes {'java.lang.Thread - ;; generated with `public-declared-method-names`, see in - ;; `comment` below - {:methods [{:name "activeCount"} + {:allPublicConstructors true + ;; generated with `public-declared-method-names`, see in + ;; `comment` below + :methods [{:name "activeCount"} {:name "checkAccess"} {:name "currentThread"} {:name "dumpStack"} diff --git a/src/babashka/impl/utils.clj b/src/babashka/impl/utils.clj index 55387bc3..8000e5ac 100644 --- a/src/babashka/impl/utils.clj +++ b/src/babashka/impl/utils.clj @@ -1,9 +1,12 @@ (ns babashka.impl.utils {:no-doc true} - (:require [sci.core :as sci])) + (:require + [sci.impl.vars :as vars] + [sci.core :as sci])) + +(sci.impl.vars/bindRoot sci/in *in*) +(sci.impl.vars/bindRoot sci/out *out*) +(sci.impl.vars/bindRoot sci/err *err*) (defn eval-string [expr ctx] - (sci/with-bindings {sci/out *out* - sci/in *in* - sci/err *err*} - (sci/eval-string expr ctx))) + (sci/eval-string expr ctx)) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 492bd252..e4286ebd 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -308,8 +308,11 @@ (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")))) + ;;;; Scratch (comment - (dotimes [i 10] (wait-for-port-test)) + (dotimes [_ 10] (wait-for-port-test)) ) diff --git a/test/babashka/test_utils.clj b/test/babashka/test_utils.clj index 5a42415d..167737c8 100644 --- a/test/babashka/test_utils.clj +++ b/test/babashka/test_utils.clj @@ -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"] From 6e99a7627b088a8850d2f84047b699119e2ffd66 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 19 Dec 2019 23:37:58 +0100 Subject: [PATCH 024/169] letfn tweak --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 95cad890..6e747f58 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 95cad890b5112448a732067b34e90b1935b6193a +Subproject commit 6e747f58504a9f59496063782e4187c0c579aeeb From 612b82e1b01af27ea2946027d2a1f405420e56dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 09:07:00 +0100 Subject: [PATCH 025/169] sci: fix re-quote-replacement --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 6e747f58..76502d11 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 6e747f58504a9f59496063782e4187c0c579aeeb +Subproject commit 76502d1116701264e85b702e8c501c1631feba4b From d9420a91bafe431980692b9bc7832f2ce61daadb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:17:11 +0100 Subject: [PATCH 026/169] v0.0.44 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index dfafd65e..2aa91601 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.44-SNAPSHOT +0.0.44 From 2243c73377c94a74725cc9131d61a90f3b912c00 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:24:07 +0100 Subject: [PATCH 027/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 5c49468d..2aa91601 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.43 +0.0.44 diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 2aa91601..2d6a47a2 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.44 +0.0.45-SNAPSHOT From 9b4f31942dab1e20cfdc3a76eb2dc7f2a3813f42 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:32:43 +0100 Subject: [PATCH 028/169] Changes --- CHANGES.md | 12 ++++++++++++ README.md | 5 +++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 CHANGES.md diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 00000000..e0320358 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,12 @@ +# Changes + +## Breaking changes + +## v0.0.44 +- #173: BREAKING: rename `*in*` to `` (in the `user` namespace). The name + was a poor choice for two reasons. It shadowed `clojure.core/*in*`. Also, the + value was not a dynamic var, but the earmuffs suggested otherwise. + +## v0.0.43 +- #160: Add support for `java.lang.ProcessBuilder`. See docs. This replaces the + `conch` namespace. diff --git a/README.md b/README.md index 348721a2..f6d33615 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# babashka +# Babashka [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) @@ -52,7 +52,8 @@ 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. For a list +of breaking changes, see [CHANGES.md](changes.md). ## Examples From d0212779d5fee24b07356c7205bc113a3ba3f853 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:33:39 +0100 Subject: [PATCH 029/169] Changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6d33615..16959b1f 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ Read more about the differences with Clojure [here](#differences-with-clojure). ## Status -Experimental. Breaking changes are expected to happen at this phase. For a list -of breaking changes, see [CHANGES.md](changes.md). +Experimental. Breaking changes are expected to happen at this phase. See see +[CHANGES.md](CHANGES.md) for a list of breaking changes. ## Examples From 9add363d0769d9d3233d1d7e9f5e15e29854d417 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:34:56 +0100 Subject: [PATCH 030/169] doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16959b1f..c5a8de16 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ Read more about the differences with Clojure [here](#differences-with-clojure). ## Status -Experimental. Breaking changes are expected to happen at this phase. See see -[CHANGES.md](CHANGES.md) for a list of breaking changes. +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 From 8c56c9ad071757adf926f1ebb520dba082dd15f6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:36:23 +0100 Subject: [PATCH 031/169] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index e0320358..04101839 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,7 @@ ## Breaking changes ## v0.0.44 -- #173: BREAKING: rename `*in*` to `` (in the `user` namespace). The name +- #173: Rename `*in*` to `` (in the `user` namespace). The name was a poor choice for two reasons. It shadowed `clojure.core/*in*`. Also, the value was not a dynamic var, but the earmuffs suggested otherwise. From 586df3d583505a610948b42ab8d1f5172afb0e82 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:45:07 +0100 Subject: [PATCH 032/169] articles --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index c5a8de16..aa730522 100644 --- a/README.md +++ b/README.md @@ -507,6 +507,14 @@ Differences with Clojure: - No support for unboxed types. +## Articles mentioning Babashka + +- [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. From 2fe5294256f2bd573680664a8f5a93607dc6bd2b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 10:46:31 +0100 Subject: [PATCH 033/169] doc --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa730522..70841bee 100644 --- a/README.md +++ b/README.md @@ -507,7 +507,9 @@ Differences with Clojure: - No support for unboxed types. -## Articles mentioning Babashka +## External resources + +### Blogs - [Advent of Random Hacks](https://lambdaisland.com/blog/2019-12-19-advent-of-parens-19-advent-of-random-hacks) From 76749fbd1777e4f775618032663892befd5d2863 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 16:51:41 +0100 Subject: [PATCH 034/169] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 70841bee..583482bc 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash. + + ## Quickstart ``` shellsession From c4f92e5b87a70d929d4a03c00d9effb6d1c178c3 Mon Sep 17 00:00:00 2001 From: Nate Sutton Date: Fri, 20 Dec 2019 10:26:28 -0600 Subject: [PATCH 035/169] Fix java.nio.file.Files in README.md (#180) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 583482bc..fc91f714 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ The following Java classes are available: - `Integer` - `Math` - `java.io.File` -- `java.nio.Files` +- `java.nio.file.Files` - `java.util.Base64` - `java.util.regex.Pattern` - `ProcessBuilder` (see [example](examples/process_builder.clj)). From 7ccbe1281a76da57e265f01f79604fce300e271c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 19:22:14 +0100 Subject: [PATCH 036/169] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index fc91f714..a7b0efc2 100644 --- a/README.md +++ b/README.md @@ -500,9 +500,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` From c1b38bfd7b3fcf9938dc9c43863bc65085476f9f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 21:17:27 +0100 Subject: [PATCH 037/169] Input and output flags --- README.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a7b0efc2..d8acfb23 100644 --- a/README.md +++ b/README.md @@ -219,11 +219,35 @@ 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 -- ``: 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 `` value may come in handy. It contains the input read from stdin and reads EDN by default. If you want to read in text, use the `-i` flag, which binds `` 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 individual 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 flags | Output flag | `` | Output | +|----------------|-------------|-------------|---------------|----------| +| `{:a 1}` | | | `{:a 1}` | `{:a 1}` | +| hello
bye | `-i` | | `("hello" "bye")` | `("hello" "bye")` | +| hello
bye | `-i` | `-o` | `("hello" "bye")` | hello
bye | +| `{:a 1} {:a 2}` | `-I` | | `({:a 1} {:a 2})` | `({:a 1} {:a 2})` | +| `{:a 1}`
`{:a 2}` | `-I` | `-O` | `({:a 1} {:a 2})` | `{:a 1}`
`{:a 2}` | + +When combined with the `--stream` option, the script is executed for each value in the input: + +``` clojure +$ echo '{:a 1} {:a 2}' | bb --stream '' +{:a 1} +{:a 2} +``` + +### Command-line arguments + +Command-line arguments can be retrieved using `*command-line-args*`. + +### Additional functions Additionally, babashka adds the following functions: From 794f0f654d44304deae43f806c734ccdb01887f7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 21:19:48 +0100 Subject: [PATCH 038/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8acfb23..505ef30b 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ conditionals](#reader-conditionals) to maintain compatibility with JVM Clojure. ### Input and output flags -In one-liners the `` value may come in handy. It contains the input read from stdin and reads EDN by default. If you want to read in text, use the `-i` flag, which binds `` 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 individual lines of text. The `-O` option prints the result as lines of EDN values. +In one-liners the `` 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 `` 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 individual 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 From ae32f6e074d821b8d66cbdb5b17f394f0840aade Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 21:20:37 +0100 Subject: [PATCH 039/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 505ef30b..3d4861ad 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ conditionals](#reader-conditionals) to maintain compatibility with JVM Clojure. ### Input and output flags -In one-liners the `` 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 `` 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 individual lines of text. The `-O` option prints the result as lines of EDN values. +In one-liners the `` 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 `` 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 From 11eea4d1d25c0a56ba7588b7691e80cf96acd69c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 21:23:51 +0100 Subject: [PATCH 040/169] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3d4861ad..f904be78 100644 --- a/README.md +++ b/README.md @@ -229,10 +229,10 @@ The following table illustrates the combination of options for commands of the f | Input | Input flags | Output flag | `` | Output | |----------------|-------------|-------------|---------------|----------| -| `{:a 1}` | | | `{:a 1}` | `{:a 1}` | +| `{:a 1}`
`{:a 2}` | | | `{:a 1}` | `{:a 1}` | | hello
bye | `-i` | | `("hello" "bye")` | `("hello" "bye")` | | hello
bye | `-i` | `-o` | `("hello" "bye")` | hello
bye | -| `{:a 1} {:a 2}` | `-I` | | `({:a 1} {:a 2})` | `({:a 1} {:a 2})` | +| `{:a 1}`
`{:a 2}` | `-I` | | `({:a 1} {:a 2})` | `({:a 1} {:a 2})` | | `{:a 1}`
`{:a 2}` | `-I` | `-O` | `({:a 1} {:a 2})` | `{:a 1}`
`{:a 2}` | When combined with the `--stream` option, the script is executed for each value in the input: From 7c45baf00805bd7cf6612d8369843515e6f92730 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 21:29:09 +0100 Subject: [PATCH 041/169] Make *command-line-args* a dynamic var --- src/babashka/main.clj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 69c50b8e..8ee62708 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -19,7 +19,8 @@ [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]) (:gen-class)) (set! *warn-on-reflection* true) @@ -239,7 +240,8 @@ Everything after that is bound to *command-line-args*.")) csv clojure.data.csv json cheshire.core} :namespaces {'clojure.core (assoc core-extras - '*command-line-args* command-line-args) + '*command-line-args* + (sci/new-dynamic-var '*command-line-args* command-line-args)) 'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read edn/read 'read-string edn/read-string} From 479a08d73e2d5df644a64e5d16b1abfcada00e21 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 23:51:24 +0100 Subject: [PATCH 042/169] [#173] becomes *input* --- CHANGES.md | 7 ++- README.md | 50 +++++++++---------- sci | 2 +- src/babashka/main.clj | 23 ++++----- test/babashka/impl/repl_test.clj | 6 +-- test/babashka/impl/socket_repl_test.clj | 10 ++-- test/babashka/main_test.clj | 64 +++++++++++++------------ 7 files changed, 83 insertions(+), 79 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 04101839..e75cccb9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,10 +2,9 @@ ## Breaking changes -## v0.0.44 -- #173: Rename `*in*` to `` (in the `user` namespace). The name - was a poor choice for two reasons. It shadowed `clojure.core/*in*`. Also, the - value was not a dynamic var, but the earmuffs suggested otherwise. +## 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 diff --git a/README.md b/README.md index f904be78..f2e977a9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas ``` shellsession $ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install) -$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) )' +$ ls | bb --time -i '(filter #(-> % io/file .isDirectory) *input*)' ("doc" "resources" "sci" "script" "src" "target" "test") bb took 4ms. ``` @@ -64,29 +64,29 @@ on [CHANGES.md](CHANGES.md) for a list of breaking changes. ## Examples ``` shellsession -$ ls | bb -i '' +$ ls | bb -i '*input*' ["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"] -$ ls | bb -i '(count )' +$ ls | bb -i '(count *input*)' 12 -$ bb '(vec (dedupe ))' <<< '[1 1 1 1 2]' +$ bb '(vec (dedupe *input*))' <<< '[1 1 1 1 2]' [1 2] -$ bb '(filterv :foo )' <<< '[{:foo 1} {:bar 2}]' +$ bb '(filterv :foo *input*)' <<< '[{:foo 1} {:bar 2}]' [{:foo 1}] -$ bb '(#(+ %1 %2 %3) 1 2 )' <<< 3 +$ bb '(#(+ %1 %2 %3) 1 2 *input*)' <<< 3 6 -$ ls | bb -i '(filterv #(re-find #"reflection" %) )' +$ ls | bb -i '(filterv #(re-find #"reflection" %) *input*)' ["reflection.json"] $ bb '(run! #(shell/sh "touch" (str "/tmp/test/" %)) (range 100))' -$ ls /tmp/test | bb -i '' +$ 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 "rino")' | bb -I '(take 3 )' +$ bb -O '(repeat "dude")' | bb --stream '(str *input* "rino")' | bb -I '(take 3 *input*)' ("duderino" "duderino" "duderino") ``` @@ -143,12 +143,12 @@ Options: --help, -h or -? Print this help text. --version Print the current version of babashka. - -i Bind to a lazy seq of lines from stdin. - -I Bind to a lazy seq of EDN values from stdin. + -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 becomes a single value per iteration. + --stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration. -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. @@ -221,13 +221,13 @@ conditionals](#reader-conditionals) to maintain compatibility with JVM Clojure. ### Input and output flags -In one-liners the `` 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 `` 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. +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}} "" + echo "{{Input}}" | bb {{Input flags}} {{Output flags}} "*input*" -| Input | Input flags | Output flag | `` | Output | +| Input | Input flags | Output flag | `*input*` | Output | |----------------|-------------|-------------|---------------|----------| | `{:a 1}`
`{:a 2}` | | | `{:a 1}` | `{:a 1}` | | hello
bye | `-i` | | `("hello" "bye")` | `("hello" "bye")` | @@ -238,7 +238,7 @@ The following table illustrates the combination of options for commands of the f When combined with the `--stream` option, the script is executed for each value in the input: ``` clojure -$ echo '{:a 1} {:a 2}' | bb --stream '' +$ echo '{:a 1} {:a 2}' | bb --stream '*input*' {:a 1} {:a 2} ``` @@ -361,7 +361,7 @@ export BABASHKA_PRELOADS Note that you can concatenate multiple expressions. Now you can use these functions in babashka: ``` shellsession -$ bb '(-> (foo ) bar)' <<< 1 +$ bb '(-> (foo *input*) bar)' <<< 1 6 ``` @@ -371,7 +371,7 @@ You can also preload an entire file using `load-file`: export BABASHKA_PRELOADS='(load-file "my_awesome_prelude.clj")' ``` -Note that `` is not available in preloads. +Note that `*input*` is not available in preloads. ## Classpath @@ -601,7 +601,7 @@ welcome! ### Delete a list of files returned by a Unix command ``` -find . | grep conflict | bb -i '(doseq [f ] (.delete (io/file f)))' +find . | grep conflict | bb -i '(doseq [f *input*] (.delete (io/file f)))' ``` ### Calculate aggregate size of directory @@ -635,7 +635,7 @@ $ cat /tmp/test.txt 3 Babashka 4 Goodbye -$ < /tmp/test.txt bb -io '(shuffle )' +$ < /tmp/test.txt bb -io '(shuffle *input*)' 3 Babashka 2 Clojure 4 Goodbye @@ -649,7 +649,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 '(-> first :name (subs 1))' +bb '(-> *input* first :name (subs 1))' "0.0.4" ``` @@ -658,8 +658,8 @@ bb '(-> first :name (subs 1))' ``` shellsession $ curl -s https://api.github.com/repos/borkdude/babashka/releases | jet --from json --keywordize | -bb '(-> first :assets)' | -bb '(some #(re-find #".*linux.*" (:browser_download_url %)) )' +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" ``` @@ -669,7 +669,7 @@ Contributed by [@plexus](https://github.com/plexus). ``` shellsession $ curl https://clojars.org/stats/all.edn | -bb -o '(for [[[group art] counts] ] (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 @@ -722,7 +722,7 @@ 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 ))] +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 diff --git a/sci b/sci index 76502d11..27893200 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 76502d1116701264e85b702e8c501c1631feba4b +Subproject commit 278932006626278a29b2ce4307d332531ff8af9d diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 8ee62708..2b8e26dc 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -138,12 +138,12 @@ (println " --help, -h or -? Print this help text. --version Print the current version of babashka. - -i Bind to a lazy seq of lines from stdin. - -I Bind to a lazy seq of EDN values from stdin. + -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 becomes a single value per iteration. + --stream Stream over lines or EDN values from stdin. Combined with -i or -I *input* becomes a single value per iteration. -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. @@ -176,16 +176,16 @@ Everything after that is bound to *command-line-args*.")) (defn start-repl! [ctx read-next] (let [ctx (update ctx :bindings assoc - (with-meta ' - {:sci/deref! true}) - (read-next))] + (with-meta '*input* + {:sci.impl/deref! true}) + (sci/new-dynamic-var '*input* (read-next)))] (repl/start-repl! ctx))) (defn start-socket-repl! [address ctx read-next] (let [ctx (update ctx :bindings assoc - (with-meta ' - {:sci/deref! true}) - (read-next))] + (with-meta '*input* + {:sci.impl/deref! true}) + (sci/new-dynamic-var '*input* (read-next)))] (socket-repl/start-repl! address ctx) ;; hang until SIGINT @(promise))) @@ -296,9 +296,10 @@ Everything after that is bound to *command-line-args*.")) (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 ' + (let [ctx (update-in ctx [:namespaces 'user] assoc (with-meta '*input* (when-not stream? - {:sci/deref! true})) in)] + {:sci.impl/deref! true})) + (sci/new-dynamic-var '*input* in))] (if (identical? ::EOF in) [nil 0] ;; done streaming (let [res [(let [res (eval-string expr ctx)] diff --git a/test/babashka/impl/repl_test.clj b/test/babashka/impl/repl_test.clj index dfe49c74..9d49344c 100644 --- a/test/babashka/impl/repl_test.clj +++ b/test/babashka/impl/repl_test.clj @@ -7,8 +7,8 @@ (set! *warn-on-reflection* true) (defn repl! [] - (start-repl! {:bindings {(with-meta ' - {:sci/deref! true}) + (start-repl! {:bindings {(with-meta '*input* + {:sci.impl/deref! true}) (delay [1 2 3]) '*command-line-args* ["a" "b" "c"]} @@ -27,7 +27,7 @@ (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 "" "[1 2 3]")) + (assert-repl "*input*" "[1 2 3]")) ;;;; Scratch diff --git a/test/babashka/impl/socket_repl_test.clj b/test/babashka/impl/socket_repl_test.clj index ad04df74..9ff3f86d 100644 --- a/test/babashka/impl/socket_repl_test.clj +++ b/test/babashka/impl/socket_repl_test.clj @@ -31,8 +31,8 @@ (deftest socket-repl-test (try (if tu/jvm? - (start-repl! "0.0.0.0:1666" {:bindings {(with-meta ' - {:sci/deref! true}) + (start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*input* + {:sci.impl/deref! true}) (delay [1 2 3]) '*command-line-args* ["a" "b" "c"]} @@ -47,8 +47,8 @@ (sh "bash" "-c" "lsof -t -i:1666")))))) (is (socket-command "(+ 1 2 3)" "user=> 6")) - (testing "" - (is (socket-command "" "[1 2 3]"))) + (testing "*input*" + (is (socket-command "*input*" "[1 2 3]"))) (testing "*command-line-args*" (is (socket-command '*command-line-args* "\"a\" \"b\" \"c\""))) (testing "&env" @@ -72,7 +72,7 @@ (dotimes [_ 1000] (t/run-tests)) (stop-repl!) - (start-repl! "0.0.0.0:1666" {:bindings {(with-meta ' + (start-repl! "0.0.0.0:1666" {:bindings {(with-meta '*input* {:sci/deref! true}) (delay [1 2 3]) '*command-line-args* diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index e4286ebd..e0ad025f 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -34,45 +34,45 @@ (deftest main-test (testing "-io behaves as identity" - (= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" ""))) + (= "foo\nbar\n" (test-utils/bb "foo\nbar\n" "-io" "*input*"))) (testing "if and when" - (is (= 1 (bb 0 '(if (zero? ) 1 2)))) - (is (= 2 (bb 1 '(if (zero? ) 1 2)))) - (is (= 1 (bb 0 '(when (zero? ) 1)))) - (is (nil? (bb 1 '(when (zero? ) 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 )))) - (is (= 0 (bb 0 '(and true true )))) - (is (= 1 (bb 1 '(or false false )))) - (is (= false (bb false '(or false false )))) - (is (= 3 (bb false '(or false false 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 %) )"))) + (is (= 2 (bb 1 "(#(+ 1 %) *input*)"))) (is (= [1 2 3] (bb 1 "(map #(+ 1 %) [0 1 2])"))) - (is (= 1 (bb 1 "(#(when (odd? ) ))")))) + (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 '(-> 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" "(->> (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 ) - :b {:a (inc )} - :c [ ] - :d #{ (inc )}})))) + (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 ))) + (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]) )") - (bb "(keep #(when (re-find #\"(?i)clojure\" (second %)) (first %)) )")))))) + "(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 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 )"))) - (is (= "2\n3\n4\n" (test-utils/bb "{:x 2} {:x 3} {:x 4}" "--stream" "(:x )"))) + (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" "")))) + (is (= x (test-utils/bb x "--stream" "-io" "*input*")))) (let [x "f\n\b\n"] - (is (= x (test-utils/bb x "--stream" "-io" "(subs 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,21 +145,21 @@ (deftest pipe-test (when test-utils/native? (let [out (:out (sh "bash" "-c" "./bb -o '(range)' | - ./bb --stream '(* )' | + ./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 \"rino\")' | - ./bb -I '(take 3 )'")) + ./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 )'")) + (let [out (:out (sh "bash" "-c" "yes | ./bb -i '(take 2 *input*)'")) out (edn/read-string out)] (is (= '("y" "y") out))))) @@ -311,6 +311,10 @@ (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*)")))) + ;;;; Scratch (comment From a8fe403d445e38ebb6738003073506e87ee147b2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 20 Dec 2019 23:55:42 +0100 Subject: [PATCH 043/169] v0.0.45 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 2d6a47a2..31c01c92 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.45-SNAPSHOT +0.0.45 From 765318f4403bd87cc704d73dc36a94e273c530f7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 00:03:11 +0100 Subject: [PATCH 044/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 2aa91601..31c01c92 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.44 +0.0.45 diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 31c01c92..22741c07 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.45 +0.0.46-SNAPSHOT From 66224bebca5d0b1187f8d384f5b066a94192ed87 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 00:06:00 +0100 Subject: [PATCH 045/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2e977a9..048a8ff5 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ The following table illustrates the combination of options for commands of the f | `{:a 1}`
`{:a 2}` | `-I` | | `({:a 1} {:a 2})` | `({:a 1} {:a 2})` | | `{:a 1}`
`{:a 2}` | `-I` | `-O` | `({:a 1} {:a 2})` | `{:a 1}`
`{:a 2}` | -When combined with the `--stream` option, the script is executed for each value in the input: +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*' From 2eecdea571256037f4590cd981d4051de25f8d7c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 11:39:28 +0100 Subject: [PATCH 046/169] [#179] Current file path: *file* --- README.md | 13 +++++++++++++ sci | 2 +- src/babashka/impl/classpath.clj | 8 +++++--- src/babashka/main.clj | 21 ++++++++++++++------- test/babashka/file_var_test.clj | 17 +++++++++++++++++ test/babashka/scripts/file_var.bb | 6 ++++++ test/babashka/scripts/file_var_classpath.bb | 1 + test/babashka/scripts/loaded_by_file_var.bb | 3 +++ 8 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 test/babashka/file_var_test.clj create mode 100644 test/babashka/scripts/file_var.bb create mode 100644 test/babashka/scripts/file_var_classpath.bb create mode 100644 test/babashka/scripts/loaded_by_file_var.bb diff --git a/README.md b/README.md index 048a8ff5..c453b7cd 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,19 @@ $ echo '{:a 1} {:a 2}' | bb --stream '*input*' {:a 2} ``` +### Current file path + +This variable `*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*`. diff --git a/sci b/sci index 27893200..abe867b9 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 278932006626278a29b2ce4307d332531ff8af9d +Subproject commit abe867b9fbc01828728e2216f17f879cc2e9e2ac diff --git a/src/babashka/impl/classpath.clj b/src/babashka/impl/classpath.clj index 1b16611f..a1846656 100644 --- a/src/babashka/impl/classpath.clj +++ b/src/babashka/impl/classpath.clj @@ -14,7 +14,8 @@ (getResource [this resource-path] (let [f (io/file path resource-path)] (when (.exists f) - (slurp f))))) + {:file (.getCanonicalPath f) + :source (slurp f)})))) (defn path-from-jar [^java.io.File jar-file path] @@ -23,7 +24,8 @@ entry (some (fn [^JarFile$JarFileEntry x] (let [nm (.getName x)] (when (and (not (.isDirectory x)) (= path nm)) - (slurp (.getInputStream jar x))))) entries)] + {:file path + :source (slurp (.getInputStream jar x))}))) entries)] entry))) (deftype JarFileResolver [path] @@ -58,5 +60,5 @@ (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) + (:file (source-for-namespace l 'cheshire.core)) ) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 2b8e26dc..be146a88 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -20,7 +20,9 @@ [clojure.java.shell :as shell] [clojure.string :as str] [sci.addons :as addons] - [sci.core :as sci]) + [sci.core :as sci] + [sci.impl.vars :as vars] + [sci.impl.namespaces :as sci-namespaces]) (:gen-class)) (set! *warn-on-reflection* true) @@ -167,9 +169,11 @@ 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))) +(defn load-file* [ctx f] + (let [f (io/file f) + s (slurp f)] + (sci/with-bindings {vars/file-var (.getCanonicalPath f)} + (eval-string s ctx)))) (defn eval* [ctx form] (eval-string (pr-str form) ctx)) @@ -230,6 +234,7 @@ Everything after that is bound to *command-line-args*.")) load-fn (when classpath (fn [{:keys [:namespace]}] (cp/source-for-namespace loader namespace))) + _ (when file (vars/bindRoot vars/file-var (.getCanonicalPath (io/file file)))) ctx {:aliases '{tools.cli 'clojure.tools.cli edn clojure.edn wait babashka.wait @@ -241,7 +246,8 @@ Everything after that is bound to *command-line-args*.")) json cheshire.core} :namespaces {'clojure.core (assoc core-extras '*command-line-args* - (sci/new-dynamic-var '*command-line-args* command-line-args)) + (sci/new-dynamic-var '*command-line-args* command-line-args) + '*file* vars/file-var) 'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read edn/read 'read-string edn/read-string} @@ -272,8 +278,9 @@ Everything after that is bound to *command-line-args*.")) 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 %)) + ctx (update-in ctx [:namespaces 'clojure.core] assoc + 'eval #(eval* ctx %) + 'load-file #(load-file* ctx %)) ctx (addons/future ctx) _preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim) (eval-string ctx)) expression (if main diff --git a/test/babashka/file_var_test.clj b/test/babashka/file_var_test.clj new file mode 100644 index 00000000..909373bb --- /dev/null +++ b/test/babashka/file_var_test.clj @@ -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")))) diff --git a/test/babashka/scripts/file_var.bb b/test/babashka/scripts/file_var.bb new file mode 100644 index 00000000..a35bf126 --- /dev/null +++ b/test/babashka/scripts/file_var.bb @@ -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*) diff --git a/test/babashka/scripts/file_var_classpath.bb b/test/babashka/scripts/file_var_classpath.bb new file mode 100644 index 00000000..9c67bd2f --- /dev/null +++ b/test/babashka/scripts/file_var_classpath.bb @@ -0,0 +1 @@ +(println *file*) diff --git a/test/babashka/scripts/loaded_by_file_var.bb b/test/babashka/scripts/loaded_by_file_var.bb new file mode 100644 index 00000000..c34fdfa2 --- /dev/null +++ b/test/babashka/scripts/loaded_by_file_var.bb @@ -0,0 +1,3 @@ +(ns loaded-by-file-var) + +(println *file*) From 9d29c6f77de6a58d3d13c0ba8c8e9a0374381d60 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 11:48:02 +0100 Subject: [PATCH 047/169] v0.0.46 --- resources/BABASHKA_VERSION | 2 +- script/bump_version.clj | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100755 script/bump_version.clj diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 22741c07..17396f8a 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.46-SNAPSHOT +0.0.46 \ No newline at end of file diff --git a/script/bump_version.clj b/script/bump_version.clj new file mode 100755 index 00000000..a615989f --- /dev/null +++ b/script/bump_version.clj @@ -0,0 +1,22 @@ +#!/usr/bin/env bb + +(ns bump-version + (:require [clojure.java.io :as io] + [clojure.string :as str])) + +(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" "")] + (spit version-file (str/join "." [major minor patch]))) + "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")] + (spit version-file (str/join "." [major minor patch])))) + (println "Expected: release | post-release.")) From 13aab1f7bc28ca0b17ade2ab1e84f7b180661f32 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 11:50:05 +0100 Subject: [PATCH 048/169] doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c453b7cd..bed3fd67 100644 --- a/README.md +++ b/README.md @@ -245,8 +245,8 @@ $ echo '{:a 1} {:a 2}' | bb --stream '*input*' ### Current file path -This variable `*file*` contains the full path of the file that is currently -being executed: +The var `*file*` contains the full path of the file that is currently being +executed: ``` shellsession $ cat example.clj From c200ec2d8b153053445ea84ced1bf99b3e13cccf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 21:05:40 +0100 Subject: [PATCH 049/169] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bed3fd67..7ba50736 100644 --- a/README.md +++ b/README.md @@ -551,6 +551,7 @@ Differences with Clojure: ### 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 From fc20ed00a3727d6e3176ddaf130a291fd6360258 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 21 Dec 2019 21:59:32 +0100 Subject: [PATCH 050/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 31c01c92..17396f8a 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.45 +0.0.46 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 17396f8a..fd19ec74 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.46 \ No newline at end of file +0.0.47-SNAPSHOT \ No newline at end of file From 34249ad0b1ba58242879edbb1c6a0f16f10a7ff5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 09:40:12 +0100 Subject: [PATCH 051/169] Add reflection info to support clj-http-lite --- reflection.json | 118 ++++++++++++++++++++++++++ script/compile | 2 + src/babashka/impl/classes.clj | 43 +++++++++- src/babashka/impl/clojure/core.clj | 1 + src/babashka/impl/clojure/java/io.clj | 1 + 5 files changed, 164 insertions(+), 1 deletion(-) diff --git a/reflection.json b/reflection.json index e010ef02..adc8aa6f 100644 --- a/reflection.json +++ b/reflection.json @@ -18,11 +18,26 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.io.ByteArrayInputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.ByteArrayOutputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.io.File", "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.io.IOException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.io.InputStream", "allPublicMethods" : true, @@ -118,6 +133,31 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.net.HttpURLConnection", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.net.URI", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.net.URLDecoder", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.net.URLEncoder", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.net.UnknownHostException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.nio.file.CopyOption", "allPublicMethods" : true, @@ -288,6 +328,41 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.util.zip.DeflaterInputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.zip.GZIPInputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.zip.GZIPOutputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.zip.InflaterInputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "javax.xml.bind.DatatypeConverter", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "sun.net.www.protocol.http.HttpURLConnection", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "sun.net.www.protocol.http.HttpURLConnection$HttpInputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "sun.nio.fs.UnixPath", "allPublicMethods" : true, @@ -363,4 +438,47 @@ "name" : "yield" } ], "name" : "java.lang.Thread" +}, { + "allPublicConstructors" : true, + "allPublicFields" : true, + "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" + }, { + "name" : "toExternalForm" + }, { + "name" : "toString" + }, { + "name" : "toURI" + } ], + "name" : "java.net.URL" } ] \ No newline at end of file diff --git a/script/compile b/script/compile index 94cb69fa..ac925a5a 100755 --- a/script/compile +++ b/script/compile @@ -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 \ diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 987197f2..e24d2015 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -8,8 +8,11 @@ clojure.lang.LineNumberingPushbackReader 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 @@ -29,6 +32,11 @@ java.lang.UNIXProcess$ProcessPipeOutputStream java.lang.ProcessBuilder java.lang.ProcessBuilder$Redirect + java.net.URI + java.net.HttpURLConnection + java.net.UnknownHostException + java.net.URLEncoder + java.net.URLDecoder java.nio.file.CopyOption java.nio.file.FileAlreadyExistsException java.nio.file.Files @@ -62,7 +70,14 @@ java.util.Base64 java.util.Base64$Decoder java.util.Base64$Encoder + java.util.zip.InflaterInputStream + java.util.zip.DeflaterInputStream + java.util.zip.GZIPInputStream + java.util.zip.GZIPOutputStream + javax.xml.bind.DatatypeConverter sun.nio.fs.UnixPath ;; included because of permission check + sun.net.www.protocol.http.HttpURLConnection ;; needed for clj-http.lite + sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; needed for clj-http.lite ] :custom-classes {'java.lang.Thread {:allPublicConstructors true @@ -100,7 +115,32 @@ {:name "sleep"} {:name "start"} {:name "toString"} - {:name "yield"}]}}}) + {: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 (:default-classes classes) @@ -148,4 +188,5 @@ (vec))) (public-declared-method-names java.lang.UNIXProcess) + (public-declared-method-names java.net.URL) ) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index 896d06a2..a1a726df 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -5,6 +5,7 @@ (def core-extras {'file-seq file-seq 'agent agent + 'instance? instance? ;; TODO: move to sci 'send send 'send-off send-off 'promise promise diff --git a/src/babashka/impl/clojure/java/io.clj b/src/babashka/impl/clojure/java/io.clj index 59e9b1f2..88e7ec0c 100644 --- a/src/babashka/impl/clojure/java/io.clj +++ b/src/babashka/impl/clojure/java/io.clj @@ -3,6 +3,7 @@ (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 From 1c5cebb608e31876402019d9a50395b4ba4731b9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 13:03:08 +0100 Subject: [PATCH 052/169] Add clojure.core/delay --- reflection.json | 5 +++++ sci | 2 +- src/babashka/impl/classes.clj | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/reflection.json b/reflection.json index adc8aa6f..3038d896 100644 --- a/reflection.json +++ b/reflection.json @@ -1,4 +1,9 @@ [ { + "name" : "clojure.lang.Delay", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { "name" : "clojure.lang.ExceptionInfo", "allPublicMethods" : true, "allPublicFields" : true, diff --git a/sci b/sci index abe867b9..acaca5fb 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit abe867b9fbc01828728e2216f17f879cc2e9e2ac +Subproject commit acaca5fb54e7b2f16ec87f32b045e88a9539272b diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index e24d2015..b8de9995 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -4,7 +4,8 @@ [cheshire.core :as json])) (def classes - {:default-classes '[clojure.lang.ExceptionInfo + {:default-classes '[clojure.lang.Delay + clojure.lang.ExceptionInfo clojure.lang.LineNumberingPushbackReader java.io.BufferedReader java.io.BufferedWriter From ebc9f6479da4c5b94e1b31b200a894732ab54063 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 17:27:06 +0100 Subject: [PATCH 053/169] Sci: remove ns when error while loading --- sci | 2 +- .../babashka/src_for_classpath_test/ns_with_error.clj | 4 ++++ test/babashka/classpath_test.clj | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test-resources/babashka/src_for_classpath_test/ns_with_error.clj diff --git a/sci b/sci index acaca5fb..9144f5ae 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit acaca5fb54e7b2f16ec87f32b045e88a9539272b +Subproject commit 9144f5ae29dc9fb710a58580411664647e848be5 diff --git a/test-resources/babashka/src_for_classpath_test/ns_with_error.clj b/test-resources/babashka/src_for_classpath_test/ns_with_error.clj new file mode 100644 index 00000000..d1f909ba --- /dev/null +++ b/test-resources/babashka/src_for_classpath_test/ns_with_error.clj @@ -0,0 +1,4 @@ +(ns ns-with-error) + +(def x 0) +(def y (/ 1 0)) diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj index b3b876d3..06117332 100644 --- a/test/babashka/classpath_test.clj +++ b/test/babashka/classpath_test.clj @@ -25,3 +25,12 @@ (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 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))")))) From fc081bda8e8e9ce13ebb7bf0784f4aadc2252693 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 17:42:21 +0100 Subject: [PATCH 054/169] Include file in error when set --- sci | 2 +- test/babashka/main_test.clj | 4 ++++ test/babashka/scripts/error.bb | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 test/babashka/scripts/error.bb diff --git a/sci b/sci index 9144f5ae..bb2fd687 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 9144f5ae29dc9fb710a58580411664647e848be5 +Subproject commit bb2fd687b962bad81088679157eb1d70b7ffc255 diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index e0ad025f..7a63b3ce 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -315,6 +315,10 @@ (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")))))) + ;;;; Scratch (comment diff --git a/test/babashka/scripts/error.bb b/test/babashka/scripts/error.bb new file mode 100644 index 00000000..f4333f8b --- /dev/null +++ b/test/babashka/scripts/error.bb @@ -0,0 +1 @@ +(/ 1 0) From 5a13134c94bd5e69f302e978bd8e81595db276e5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 19:28:42 +0100 Subject: [PATCH 055/169] sci: add condp --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index bb2fd687..20980cfb 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit bb2fd687b962bad81088679157eb1d70b7ffc255 +Subproject commit 20980cfb594dcddf4bab06bcb141450c4674a6ed From 4ca9a81c1c37d1aa87c13662240e5f72981dce40 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 19:43:13 +0100 Subject: [PATCH 056/169] sci: fix exclude --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 20980cfb..577351c5 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 20980cfb594dcddf4bab06bcb141450c4674a6ed +Subproject commit 577351c5514edb7492314048aef99d3c4319a667 From 3270d521d3d3eb5671cd48286f003eda82b40998 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 20:09:52 +0100 Subject: [PATCH 057/169] Support for clj-http-lite --- reflection.json | 20 +++---- sci | 2 +- src/babashka/impl/classes.clj | 4 +- src/babashka/main.clj | 101 +++++++++++++++++----------------- test/babashka/main_test.clj | 3 + 5 files changed, 68 insertions(+), 62 deletions(-) diff --git a/reflection.json b/reflection.json index 3038d896..c2e35bed 100644 --- a/reflection.json +++ b/reflection.json @@ -188,6 +188,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.nio.file.Paths", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.nio.file.StandardCopyOption", "allPublicMethods" : true, @@ -353,21 +358,16 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true -}, { - "name" : "javax.xml.bind.DatatypeConverter", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.net.www.protocol.http.HttpURLConnection", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true }, { "name" : "sun.net.www.protocol.http.HttpURLConnection$HttpInputStream", "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "sun.net.www.protocol.https.HttpsURLConnectionImpl", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "sun.nio.fs.UnixPath", "allPublicMethods" : true, diff --git a/sci b/sci index 577351c5..6b75e107 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 577351c5514edb7492314048aef99d3c4319a667 +Subproject commit 6b75e1071ee425c6f468c73b2cef3ceae9c24af5 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index b8de9995..20e27ee6 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -43,6 +43,7 @@ java.nio.file.Files 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.PosixFilePermission @@ -75,9 +76,8 @@ java.util.zip.DeflaterInputStream java.util.zip.GZIPInputStream java.util.zip.GZIPOutputStream - javax.xml.bind.DatatypeConverter sun.nio.fs.UnixPath ;; included because of permission check - sun.net.www.protocol.http.HttpURLConnection ;; needed for clj-http.lite + sun.net.www.protocol.https.HttpsURLConnectionImpl ;; needed fo clj-http.lite sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; needed for clj-http.lite ] :custom-classes {'java.lang.Thread diff --git a/src/babashka/main.clj b/src/babashka/main.clj index be146a88..1f62b057 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -21,8 +21,7 @@ [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] - [sci.impl.vars :as vars] - [sci.impl.namespaces :as sci-namespaces]) + [sci.impl.vars :as vars]) (:gen-class)) (set! *warn-on-reflection* true) @@ -169,6 +168,8 @@ Everything after that is bound to *command-line-args*.")) (edn/read {;;:readers *data-readers* :eof ::EOF} *in*)) +(def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false)) + (defn load-file* [ctx f] (let [f (io/file f) s (slurp f)] @@ -247,7 +248,8 @@ Everything after that is bound to *command-line-args*.")) :namespaces {'clojure.core (assoc core-extras '*command-line-args* (sci/new-dynamic-var '*command-line-args* command-line-args) - '*file* vars/file-var) + '*file* vars/file-var + '*warn-on-reflection* reflection-var) 'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read edn/read 'read-string edn/read-string} @@ -288,52 +290,53 @@ Everything after that is bound to *command-line-args*.")) main) expression) 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 '*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 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) + (sci/with-bindings {reflection-var false} + (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 '*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 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)) t1 (System/currentTimeMillis)] (when time? (binding [*out* *err*] (println "bb took" (str (- t1 t0) "ms.")))) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 7a63b3ce..da304cbb 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -319,6 +319,9 @@ (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)")))) + ;;;; Scratch (comment From d124288a56daa059e3e1f0f9c55e37afa7980569 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 20:30:53 +0100 Subject: [PATCH 058/169] v0.0.47 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index fd19ec74..03a05cda 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.47-SNAPSHOT \ No newline at end of file +0.0.47 \ No newline at end of file From b1e4e4297fcc69412549b4406c65822bf541dd83 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 20:52:07 +0100 Subject: [PATCH 059/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 17396f8a..03a05cda 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.46 \ No newline at end of file +0.0.47 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 03a05cda..9b5a4d5c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.47 \ No newline at end of file +0.0.48-SNAPSHOT \ No newline at end of file From 2ab73f2342e82c7bccf9d4c68ff55b9614b0ebf2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 22:10:22 +0100 Subject: [PATCH 060/169] Add class to make (client/get "http://...") work --- reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + 2 files changed, 6 insertions(+) diff --git a/reflection.json b/reflection.json index c2e35bed..419388bc 100644 --- a/reflection.json +++ b/reflection.json @@ -358,6 +358,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "sun.net.www.protocol.http.HttpURLConnection", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "sun.net.www.protocol.http.HttpURLConnection$HttpInputStream", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 20e27ee6..0eb5d5c2 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -78,6 +78,7 @@ java.util.zip.GZIPOutputStream sun.nio.fs.UnixPath ;; included because of permission check sun.net.www.protocol.https.HttpsURLConnectionImpl ;; needed fo clj-http.lite + sun.net.www.protocol.http.HttpURLConnection ;; needed for clj.http.lite http calls sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; needed for clj-http.lite ] :custom-classes {'java.lang.Thread From 33975bc9c4029da9161ac21d9dd176a94c229849 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 22:46:37 +0100 Subject: [PATCH 061/169] v0.0.48 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 9b5a4d5c..57444e0c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.48-SNAPSHOT \ No newline at end of file +0.0.48 \ No newline at end of file From 0462c0fd61a60d9185bc0cc986b47f8df6aba73e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 22 Dec 2019 23:01:53 +0100 Subject: [PATCH 062/169] Bump version --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 03a05cda..57444e0c 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.47 \ No newline at end of file +0.0.48 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 57444e0c..eb5eb479 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.48 \ No newline at end of file +0.0.49-SNAPSHOT \ No newline at end of file From 1835d7d219cd4fe4932c028025204412990eed66 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 23 Dec 2019 11:12:20 +0100 Subject: [PATCH 063/169] Get rid of Python in tests --- test/babashka/main_test.clj | 22 +++++++--------------- test/babashka/test_utils.clj | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index da304cbb..7370cc72 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -7,7 +7,8 @@ [clojure.java.shell :refer [sh]] [clojure.string :as str] [clojure.test :as test :refer [deftest is testing]] - [sci.core :as sci])) + [sci.core :as sci] + [babashka.test-utils :as tu])) (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) @@ -170,7 +171,7 @@ (is (str/includes? (bb nil " (def ls (-> (ProcessBuilder. [\"ls\"]) (.start))) (def output (.getInputStream ls)) -(.waitFor ls) +(assert (int? (.waitFor ls))) (slurp output)") "LICENSE"))) @@ -185,19 +186,10 @@ temp-dir-path)))))) (deftest wait-for-port-test - (is (= :timed-out - (bb nil "(def ws (-> (ProcessBuilder. [\"python\" \"-m\" \"SimpleHTTPServer\" \"1777\"]) (.start))) - (wait/wait-for-port \"127.0.0.1\" 1777) - (.destroy ws) - (.waitFor ws) - (wait/wait-for-port \"localhost\" 1777 {:default :timed-out :timeout 50})"))) - (is (int? (bb nil " -(require '[babashka.wait :as wait]) -(def ws (-> (ProcessBuilder. [\"python\" \"-m\" \"SimpleHTTPServer\" \"1777\"]) (.start))) -(wait/wait-for-port \"localhost\" 1777) -(slurp \"http://localhost:1777\") -(.destroy ws) -(.waitFor ws)")))) + (let [server (tu/start-server! 1777)] + (is (= 1777 (:port (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777)")))) + (tu/stop-server! server) + (is (= :timed-out (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777 {:default :timed-out :timeout 50})"))))) (deftest wait-for-path-test (let [temp-dir-path (System/getProperty "java.io.tmpdir")] diff --git a/test/babashka/test_utils.clj b/test/babashka/test_utils.clj index 167737c8..071e263c 100644 --- a/test/babashka/test_utils.clj +++ b/test/babashka/test_utils.clj @@ -58,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)) From acfc79660a87738d779e27b7ff2cb603b5eea7ff Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 10:01:32 +0100 Subject: [PATCH 064/169] [#154] Expose clojure.main/repl to babashka --- README.md | 4 +- sci | 2 +- src/babashka/impl/clojure/core/server.clj | 9 +- src/babashka/impl/clojure/main.clj | 25 +---- src/babashka/impl/repl.clj | 106 +++++++++++++--------- src/babashka/impl/socket_repl.clj | 6 +- src/babashka/main.clj | 47 +++++----- test/babashka/impl/repl_test.clj | 28 +++--- test/babashka/impl/socket_repl_test.clj | 16 ++-- test/babashka/main_test.clj | 20 ++-- 10 files changed, 135 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 7ba50736..bdcc0bc1 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,9 @@ enumerated explicitly. - `clojure.java.shell` aliases as `shell`: - `sh` - `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`, `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. diff --git a/sci b/sci index 6b75e107..79563a0c 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 6b75e1071ee425c6f468c73b2cef3ceae9c24af5 +Subproject commit 79563a0c94daa11e56e0969c963a52af9f7ee00f diff --git a/src/babashka/impl/clojure/core/server.clj b/src/babashka/impl/clojure/core/server.clj index ea6f14c8..2b1c821f 100644 --- a/src/babashka/impl/clojure/core/server.clj +++ b/src/babashka/impl/clojure/core/server.clj @@ -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) diff --git a/src/babashka/impl/clojure/main.clj b/src/babashka/impl/clojure/main.clj index b7c9010a..43e2b434 100644 --- a/src/babashka/impl/clojure/main.clj +++ b/src/babashka/impl/clojure/main.clj @@ -15,9 +15,7 @@ :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])) (defmacro with-bindings "Executes body in the context of thread-local bindings for several vars @@ -44,18 +42,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 +78,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.) diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index d97cec3a..ddb89594 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -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 *err* #_@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) + ) diff --git a/src/babashka/impl/socket_repl.clj b/src/babashka/impl/socket_repl.clj index 13195287..a18025b9 100644 --- a/src/babashka/impl/socket_repl.clj +++ b/src/babashka/impl/socket_repl.clj @@ -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 diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 1f62b057..9a823a95 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -21,7 +21,9 @@ [clojure.string :as str] [sci.addons :as addons] [sci.core :as sci] - [sci.impl.vars :as vars]) + [sci.impl.opts :as sci-opts] + [sci.impl.vars :as vars] + [sci.impl.interpreter :refer [eval-string*]]) (:gen-class)) (set! *warn-on-reflection* true) @@ -179,21 +181,10 @@ Everything after that is bound to *command-line-args*.")) (defn eval* [ctx form] (eval-string (pr-str form) ctx)) -(defn start-repl! [ctx read-next] - (let [ctx (update ctx :bindings assoc - (with-meta '*input* - {:sci.impl/deref! true}) - (sci/new-dynamic-var '*input* (read-next)))] - (repl/start-repl! ctx))) - -(defn start-socket-repl! [address ctx read-next] - (let [ctx (update ctx :bindings assoc - (with-meta '*input* - {:sci.impl/deref! true}) - (sci/new-dynamic-var '*input* (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}))) @@ -283,12 +274,17 @@ Everything after that is bound to *command-line-args*.")) ctx (update-in ctx [:namespaces 'clojure.core] assoc 'eval #(eval* ctx %) 'load-file #(load-file* ctx %)) + ctx (assoc-in ctx [:namespaces 'clojure.main 'repl] + (fn [& opts] + (let [opts (apply hash-map opts)] + (repl/start-repl! ctx opts)))) 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) exit-code (sci/with-bindings {reflection-var false} (or @@ -299,20 +295,21 @@ Everything after that is bound to *command-line-args*.")) [(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] + repl [(repl/start-repl! sci-ctx) 0] + socket-repl [(start-socket-repl! socket-repl sci-ctx) 0] :else (try - (let [expr (if file (read-file file) expression)] + (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 '*input* - (when-not stream? - {:sci.impl/deref! true})) - (sci/new-dynamic-var '*input* 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 expr ctx)] + (let [res [(let [res (eval-string* sci-ctx expr)] (when (some? res) (if-let [pr-f (cond shell-out println edn-out prn)] @@ -325,7 +322,7 @@ Everything after that is bound to *command-line-args*.")) (if stream? (recur (read-next *in*)) res))))) - [(start-repl! ctx #(read-next *in*)) 0])) + [(repl/start-repl! sci-ctx) 0])) (catch Throwable e (binding [*out* *err*] (let [d (ex-data e) diff --git a/test/babashka/impl/repl_test.clj b/test/babashka/impl/repl_test.clj index 9d49344c..d0f1bc5b 100644 --- a/test/babashka/impl/repl_test.clj +++ b/test/babashka/impl/repl_test.clj @@ -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 '*input* - {:sci.impl/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 "*input*" "[1 2 3]")) + (assert-repl "*command-line-args*" "[\"a\" \"b\" \"c\"]")) ;;;; Scratch diff --git a/test/babashka/impl/socket_repl_test.clj b/test/babashka/impl/socket_repl_test.clj index 9ff3f86d..83038f0e 100644 --- a/test/babashka/impl/socket_repl_test.clj +++ b/test/babashka/impl/socket_repl_test.clj @@ -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 '*input* - {:sci.impl/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 "*input*" - (is (socket-command "*input*" "[1 2 3]"))) (testing "*command-line-args*" (is (socket-command '*command-line-args* "\"a\" \"b\" \"c\""))) (testing "&env" diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 7370cc72..374a1af7 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -7,8 +7,7 @@ [clojure.java.shell :refer [sh]] [clojure.string :as str] [clojure.test :as test :refer [deftest is testing]] - [sci.core :as sci] - [babashka.test-utils :as tu])) + [sci.core :as sci])) (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) @@ -186,9 +185,9 @@ temp-dir-path)))))) (deftest wait-for-port-test - (let [server (tu/start-server! 1777)] + (let [server (test-utils/start-server! 1777)] (is (= 1777 (:port (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777)")))) - (tu/stop-server! server) + (test-utils/stop-server! server) (is (= :timed-out (bb nil "(wait/wait-for-port \"127.0.0.1\" 1777 {:default :timed-out :timeout 50})"))))) (deftest wait-for-path-test @@ -314,8 +313,15 @@ (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 \"> \")))))"))) + ;;;; Scratch -(comment - (dotimes [_ 10] (wait-for-port-test)) - ) + (comment + (dotimes [_ 10] (wait-for-port-test)) + )) From 2041656583f97d69f818e422d183478fd46fc6d4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 10:24:41 +0100 Subject: [PATCH 065/169] [#154] minor --- src/babashka/impl/repl.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/babashka/impl/repl.clj b/src/babashka/impl/repl.clj index ddb89594..3460aaeb 100644 --- a/src/babashka/impl/repl.clj +++ b/src/babashka/impl/repl.clj @@ -13,7 +13,7 @@ (defn repl-caught "Default :caught hook for repl" [e] - (sci/with-bindings {sci/out *err* #_@sci/err} + (sci/with-bindings {sci/out @sci/err} (sio/println (.getMessage ^Exception e)) (sio/flush))) From b5553f157a28dd5cf504fdd8738a12111bdf629d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 10:25:00 +0100 Subject: [PATCH 066/169] v0.0.49 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index eb5eb479..f55b2502 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.49-SNAPSHOT \ No newline at end of file +0.0.49 \ No newline at end of file From 91a7b9a3c40b3560878615a63561301f493f06ed Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 10:35:08 +0100 Subject: [PATCH 067/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 57444e0c..f55b2502 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.48 \ No newline at end of file +0.0.49 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index f55b2502..45e4ba0c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.49 \ No newline at end of file +0.0.50-SNAPSHOT \ No newline at end of file From 978809330654ff6accfb71d257182f12a0f01664 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 10:41:01 +0100 Subject: [PATCH 068/169] Enhance bump version script --- script/bump_version.clj | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/script/bump_version.clj b/script/bump_version.clj index a615989f..5addd96f 100755 --- a/script/bump_version.clj +++ b/script/bump_version.clj @@ -2,7 +2,8 @@ (ns bump-version (:require [clojure.java.io :as io] - [clojure.string :as str])) + [clojure.string :as str] + [clojure.java.shell :refer [sh]])) (def version-file (io/file "resources" "BABASHKA_VERSION")) (def released-version-file (io/file "resources" "BABASHKA_RELEASED_VERSION")) @@ -10,13 +11,18 @@ (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" "")] - (spit version-file (str/join "." [major minor patch]))) + patch (str/replace patch "-SNAPSHOT" "") + new-version (str/join "." [major minor patch])] + (spit version-file new-version) + (sh "git" "commit" "-a" "-m" (str "v" new-version)) + (println (:out (sh "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")] - (spit version-file (str/join "." [major minor patch])))) + patch (str (inc patch) "-SNAPSHOT") + new-version (str/join "." [major minor patch])] + (spit version-file new-version) + (sh "git" "commit" "-a" "-m" "Version bump"))) (println "Expected: release | post-release.")) From c339f628ad050033ccc020881feee76caece5b75 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 24 Dec 2019 11:31:31 +0100 Subject: [PATCH 069/169] libs --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index bdcc0bc1..428c0e76 100644 --- a/README.md +++ b/README.md @@ -551,6 +551,37 @@ Differences with Clojure: ## External resources +### Libraries + +The following libraries are known to work with Babashka: + +#### [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 {limit-break {: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 From 4ed7e7bf27b39255e34cce96a3cf6036f71f6d53 Mon Sep 17 00:00:00 2001 From: Nikita Prokopov Date: Tue, 24 Dec 2019 14:46:51 +0100 Subject: [PATCH 070/169] Logo --- README.md | 2 +- logo/babashka.png | Bin 0 -> 65486 bytes logo/babashka.svg | 30 ++++++++++++++++++++++++++++++ logo/icon.png | Bin 0 -> 7748 bytes logo/icon.svg | 18 ++++++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 logo/babashka.png create mode 100644 logo/babashka.svg create mode 100644 logo/icon.png create mode 100644 logo/icon.svg diff --git a/README.md b/README.md index 428c0e76..6b363192 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Babashka + [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) diff --git a/logo/babashka.png b/logo/babashka.png new file mode 100644 index 0000000000000000000000000000000000000000..f042bf5e650d3b2f54982dc6a9837734a2687926 GIT binary patch literal 65486 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 literal 0 HcmV?d00001 diff --git a/logo/babashka.svg b/logo/babashka.svg new file mode 100644 index 00000000..f3f63ee5 --- /dev/null +++ b/logo/babashka.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/logo/icon.png b/logo/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b1dd077cb46a56fdd996c3515631ea1dad18df3b GIT binary patch literal 7748 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

XrAU=S_@KjRa424Ye;+gS1mB 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 KMNUMnLSTaJf6r+E literal 0 HcmV?d00001 diff --git a/logo/icon.svg b/logo/icon.svg new file mode 100644 index 00000000..ef89d121 --- /dev/null +++ b/logo/icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 4788969b1144f425b1816a777899a62669f2d2ca Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Dec 2019 14:49:29 +0100 Subject: [PATCH 071/169] Update README.md --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6b363192..e6611cd9 100644 --- a/README.md +++ b/README.md @@ -551,13 +551,18 @@ Differences with Clojure: ## External resources -### Libraries +### 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. + #### [clj-http-lite](https://github.com/borkdude/clj-http-lite) - This fork does not depend on any other libraries. Example: +This fork does not depend on any other libraries. Example: ``` shell $ export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {limit-break {:git/url "https://github.com/borkdude/clj-http-lite" :sha "f44ebe45446f0f44f2b73761d102af3da6d0a13e"}}}' -Spath)" @@ -568,7 +573,7 @@ $ bb "(require '[clj-http.lite.client :as client]) (:status (client/get \"https: #### [limit-break](https://github.com/technomancy/limit-break) - A debug REPL library. Example: +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)" From 5ad851d2edf267ebfbf41492ab94e12a877fa844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Santiago?= Date: Wed, 25 Dec 2019 14:55:49 +0000 Subject: [PATCH 072/169] Add missing functions from cheshire.core (#195) --- src/babashka/impl/cheshire.clj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/babashka/impl/cheshire.clj b/src/babashka/impl/cheshire.clj index 21faa7ba..76cc4180 100644 --- a/src/babashka/impl/cheshire.clj +++ b/src/babashka/impl/cheshire.clj @@ -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}) From edecf87b67b1e9f049a6ec981a8e4fd6d2483bb0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Dec 2019 16:14:28 +0100 Subject: [PATCH 073/169] [#194] *command-line-args* should be nil instead of empty list when no args are provided --- src/babashka/main.clj | 139 ++++++++++++++++++------------------ test/babashka/main_test.clj | 18 +++-- 2 files changed, 81 insertions(+), 76 deletions(-) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 9a823a95..51e9b983 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -34,77 +34,78 @@ (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)) + ("-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)))) + ("--classpath", "-cp") + (let [options (next options)] + (recur (next options) + (assoc opts-map :classpath (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)) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 374a1af7..53f5d303 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -21,15 +21,15 @@ (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 @@ -318,10 +318,14 @@ (defn foo [] (println \"foo!\")) (with-out-str (with-in-str \"(foo)\" - (clojure.main/repl :init (fn []) :prompt (fn [] (print \"> \")))))"))) + (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")))) ;;;; Scratch - (comment - (dotimes [_ 10] (wait-for-port-test)) - )) +(comment + (dotimes [_ 10] (wait-for-port-test)) + ) From 68e061762c1aa49090c281877b550f4bd0fe2782 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Dec 2019 16:21:39 +0100 Subject: [PATCH 074/169] v0.0.50 --- resources/BABASHKA_VERSION | 2 +- src-bash/bbk | 219 ------------------------------------- 2 files changed, 1 insertion(+), 220 deletions(-) delete mode 100755 src-bash/bbk diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 45e4ba0c..789511e7 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.50-SNAPSHOT \ No newline at end of file +0.0.50 \ No newline at end of file diff --git a/src-bash/bbk b/src-bash/bbk deleted file mode 100755 index 38b6c36e..00000000 --- a/src-bash/bbk +++ /dev/null @@ -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 From c446dced0e05c86e7e800a14c5879ba551e0aef1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Dec 2019 16:32:43 +0100 Subject: [PATCH 075/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- script/bump_version.clj | 42 +++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index f55b2502..789511e7 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.49 \ No newline at end of file +0.0.50 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 789511e7..38c0191e 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.50 \ No newline at end of file +0.0.51-SNAPSHOT \ No newline at end of file diff --git a/script/bump_version.clj b/script/bump_version.clj index 5addd96f..6a3591bd 100755 --- a/script/bump_version.clj +++ b/script/bump_version.clj @@ -2,8 +2,39 @@ (ns bump-version (:require [clojure.java.io :as io] - [clojure.string :as str] - [clojure.java.shell :refer [sh]])) + [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")) @@ -14,8 +45,8 @@ patch (str/replace patch "-SNAPSHOT" "") new-version (str/join "." [major minor patch])] (spit version-file new-version) - (sh "git" "commit" "-a" "-m" (str "v" new-version)) - (println (:out (sh "git" "diff" "HEAD^" "HEAD")))) + (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)) @@ -24,5 +55,6 @@ patch (str (inc patch) "-SNAPSHOT") new-version (str/join "." [major minor patch])] (spit version-file new-version) - (sh "git" "commit" "-a" "-m" "Version bump"))) + (shell-command ["git" "commit" "-a" "-m" "Version bump"]) + (shell-command ["git" "diff" "HEAD^" "HEAD"]))) (println "Expected: release | post-release.")) From ded6dd235540c56772c915be7079d6b513ed6ad6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 22:52:56 +0100 Subject: [PATCH 076/169] --uberscript option (#197) --- README.md | 71 +++++++--- resources/BABASHKA_VERSION | 2 +- sci | 2 +- src/babashka/impl/utils.clj | 12 -- src/babashka/main.clj | 234 ++++++++++++++++++------------- test/babashka/classpath_test.clj | 7 + 6 files changed, 198 insertions(+), 130 deletions(-) delete mode 100644 src/babashka/impl/utils.clj diff --git a/README.md b/README.md index e6611cd9..4663a60e 100644 --- a/README.md +++ b/README.md @@ -137,25 +137,26 @@ You may also download a binary from [Github](https://github.com/borkdude/babashk Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] [ ( --classpath | -cp ) ] [ ( --main | -m ) ] ( -e | -f | --repl | --socket-repl [:] ) - [ arg* ] + [ --uberscript ] [ arg* ] Options: - --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. - -e, --eval Evaluate an expression. - -f, --file Evaluate a file. - -cp, --classpath Classpath to use. - -m, --main 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. + -e, --eval Evaluate an expression. + -f, --file Evaluate a file. + -cp, --classpath Classpath to use. + -m, --main Call the -main function from namespace with args. + --uberscript Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. + --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*. @@ -408,10 +409,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 @@ -428,6 +429,36 @@ $ bb "(my-gist-script/-main)" Hello from gist script! ``` +Using the [deps.clj](https://github.com/borkdude/deps.clj/) script, you can also +pass the classpath and main opts to `bb`: + +``` shell +$ deps.clj -A:my-script -Scommand "bb my_script.clj {{main-opts}}" +Hello from gist script! +``` + +## 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 purposes and deployment. + +Given the `deps.edn` from above: + +``` shell +$ deps.clj -A:my-script -Scommand "bb {{main-opts}} --uberscript my-script.clj" + +$ cat my-script.clj +(ns my-gist-script) +(defn -main [& args] + (println "Hello from gist script!"))(require '[my-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`: diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 38c0191e..ba4921ce 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.51-SNAPSHOT \ No newline at end of file +0.0.51 \ No newline at end of file diff --git a/sci b/sci index 79563a0c..92f2251f 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 79563a0c94daa11e56e0969c963a52af9f7ee00f +Subproject commit 92f2251fcc2ca795db05e78605e1c78bb8462884 diff --git a/src/babashka/impl/utils.clj b/src/babashka/impl/utils.clj deleted file mode 100644 index 8000e5ac..00000000 --- a/src/babashka/impl/utils.clj +++ /dev/null @@ -1,12 +0,0 @@ -(ns babashka.impl.utils - {:no-doc true} - (:require - [sci.impl.vars :as vars] - [sci.core :as sci])) - -(sci.impl.vars/bindRoot sci/in *in*) -(sci.impl.vars/bindRoot sci/out *out*) -(sci.impl.vars/bindRoot sci/err *err*) - -(defn eval-string [expr ctx] - (sci/eval-string expr ctx)) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 51e9b983..7f34a985 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -13,7 +13,6 @@ [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.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] @@ -26,6 +25,10 @@ [sci.impl.interpreter :refer [eval-string*]]) (:gen-class)) +(sci.impl.vars/bindRoot sci/in *in*) +(sci.impl.vars/bindRoot sci/out *out*) +(sci.impl.vars/bindRoot sci/err *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 '...' @@ -68,6 +71,15 @@ (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) @@ -87,10 +99,6 @@ (let [options (next options)] (recur (next options) (assoc opts-map :expression (first options)))) - ("--classpath", "-cp") - (let [options (next options)] - (recur (next options) - (assoc opts-map :classpath (first options)))) ("--main", "-m") (let [options (next options)] (recur (next options) @@ -128,7 +136,7 @@ (def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] [ ( --classpath | -cp ) ] [ ( --main | -m ) ] ( -e | -f | --repl | --socket-repl [:] ) - [ arg* ]") + [ --uberscript ] [ arg* ]") (defn print-usage [] (println usage-string)) @@ -140,21 +148,22 @@ (println) (println "Options:") (println " - --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. - -e, --eval Evaluate an expression. - -f, --file Evaluate a file. - -cp, --classpath Classpath to use. - -m, --main 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. + -e, --eval Evaluate an expression. + -f, --file Evaluate a file. + -cp, --classpath Classpath to use. + -m, --main Call the -main function from namespace with args. + --uberscript Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. + --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*.")) @@ -173,14 +182,14 @@ Everything after that is bound to *command-line-args*.")) (def reflection-var (sci/new-dynamic-var '*warn-on-reflection* false)) -(defn load-file* [ctx f] +(defn load-file* [sci-ctx f] (let [f (io/file f) s (slurp f)] (sci/with-bindings {vars/file-var (.getCanonicalPath f)} - (eval-string s ctx)))) + (eval-string* sci-ctx s)))) -(defn eval* [ctx form] - (eval-string (pr-str form) ctx)) +(defn eval* [sci-ctx form] + (eval-string* sci-ctx (pr-str form))) (defn start-socket-repl! [address ctx] (socket-repl/start-repl! address ctx) @@ -194,6 +203,45 @@ 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 {'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 + 'clojure.core.async async-namespace + 'clojure.data.csv csv/csv-namespace + 'cheshire.core cheshire-core-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!) @@ -205,7 +253,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?) @@ -219,6 +267,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")) @@ -226,35 +275,18 @@ 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))) + (let [res (cp/source-for-namespace loader namespace)] + (when uberscript (swap! uberscript-sources conj (:source res))) + res))) _ (when file (vars/bindRoot vars/file-var (.getCanonicalPath (io/file file)))) - ctx {: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} - :namespaces {'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) - 'clojure.tools.cli tools-cli-namespace - 'clojure.edn {'read edn/read - '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 - 'clojure.core.async async-namespace - 'clojure.data.csv csv/csv-namespace - 'cheshire.core cheshire-core-namespace} - :bindings {'java.lang.System/exit exit ;; override exit, so we have more control - 'System/exit exit} + ctx {:aliases aliases + :namespaces (assoc namespaces '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)) + :bindings bindings :env env :features #{:bb} :classes classes/class-map @@ -271,37 +303,47 @@ Everything after that is bound to *command-line-args*.")) String java.lang.String System java.lang.System Thread java.lang.Thread} - :load-fn load-fn} - ctx (update-in ctx [:namespaces 'clojure.core] assoc - 'eval #(eval* ctx %) - 'load-file #(load-file* ctx %)) - ctx (assoc-in ctx [:namespaces 'clojure.main 'repl] - (fn [& opts] - (let [opts (apply hash-map opts)] - (repl/start-repl! ctx opts)))) + :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?)))) + expression (str (when preloads + (str preloads "\n")) + expression) 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] - :else - (try - (let [ expr (if file (read-file file) expression)] - (if expr + (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] + expression + (try (loop [in (read-next *in*)] (let [_ (swap! env update-in [:namespaces 'user] assoc (with-meta '*input* @@ -310,7 +352,7 @@ Everything after that is bound to *command-line-args*.")) (sci/new-dynamic-var '*input* in))] (if (identical? ::EOF in) [nil 0] ;; done streaming - (let [res [(let [res (eval-string* sci-ctx expr)] + (let [res [(let [res (eval-string* sci-ctx expression)] (when (some? res) (if-let [pr-f (cond shell-out println edn-out prn)] @@ -323,22 +365,22 @@ Everything after that is bound to *command-line-args*.")) (if stream? (recur (read-next *in*)) res))))) - [(repl/start-repl! sci-ctx) 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)) + (catch Throwable e + (error-handler* e verbose?))) + :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 expression :append true) + (spit uberscript-out file :append true))) (when time? (binding [*out* *err*] (println "bb took" (str (- t1 t0) "ms.")))) - (flush) exit-code)) (defn -main diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj index 06117332..24048ade 100644 --- a/test/babashka/classpath_test.clj +++ b/test/babashka/classpath_test.clj @@ -26,6 +26,13 @@ (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" From db95d9b788ae4b3686ad36cd038e35d8cf766aae Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 22:53:20 +0100 Subject: [PATCH 077/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4663a60e..b9846a0e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) From f6e12848183ef9c9f9557bb8b79f4e08f57cd807 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 22:55:01 +0100 Subject: [PATCH 078/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9846a0e..70c28723 100644 --- a/README.md +++ b/README.md @@ -439,7 +439,7 @@ Hello from gist script! ## Uberscript -The `--uberscript ` option collects the expressions in +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 purposes and deployment. From 21b4a0f68ad1e14d4f3b53fc2913a95a8959c2d8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:03:30 +0100 Subject: [PATCH 079/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 789511e7..ba4921ce 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.50 \ No newline at end of file +0.0.51 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index ba4921ce..470d58fc 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.51 \ No newline at end of file +0.0.52-SNAPSHOT \ No newline at end of file From e8606359b1d7d6dfe34e7cf22845955cb7e3cf24 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:04:38 +0100 Subject: [PATCH 080/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70c28723..08d8d68e 100644 --- a/README.md +++ b/README.md @@ -446,7 +446,7 @@ convenient for debugging purposes and deployment. Given the `deps.edn` from above: -``` shell +``` clojure $ deps.clj -A:my-script -Scommand "bb {{main-opts}} --uberscript my-script.clj" $ cat my-script.clj From 0f5a399160d0f073ddd129ba896af482f64e8af1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:06:48 +0100 Subject: [PATCH 081/169] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08d8d68e..20eb2bb7 100644 --- a/README.md +++ b/README.md @@ -433,7 +433,7 @@ Using the [deps.clj](https://github.com/borkdude/deps.clj/) script, you can also pass the classpath and main opts to `bb`: ``` shell -$ deps.clj -A:my-script -Scommand "bb my_script.clj {{main-opts}}" +$ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}}" Hello from gist script! ``` @@ -447,7 +447,7 @@ convenient for debugging purposes and deployment. Given the `deps.edn` from above: ``` clojure -$ deps.clj -A:my-script -Scommand "bb {{main-opts}} --uberscript my-script.clj" +$ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}} --uberscript my-script.clj" $ cat my-script.clj (ns my-gist-script) From c5ec9303226c1f875e1a19563bf940888e9425bf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:11:25 +0100 Subject: [PATCH 082/169] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20eb2bb7..5c44c114 100644 --- a/README.md +++ b/README.md @@ -452,8 +452,8 @@ $ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}} --uberscri $ cat my-script.clj (ns my-gist-script) (defn -main [& args] - (println "Hello from gist script!"))(require '[my-gist-script]) -(ns user (:require [my-gist-script])) (apply my-gist-script/-main *command-line-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! From 4522345685a2cdfc34ddb76ccaea0db495217ecd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:18:44 +0100 Subject: [PATCH 083/169] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5c44c114..70a25a2e 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,8 @@ 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 will take longer than a few seconds, using Clojure on the JVM may be a better fit. Read more about the differences with Clojure [here](#differences-with-clojure). From 5840706858cf851a210f424b9d334a4e02961339 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:19:38 +0100 Subject: [PATCH 084/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70a25a2e..fb84a512 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Non-goals: * Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. Babashka uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci -implements a subset of Clojure and is not as performant as compiled code. If your script will take longer than a few seconds, using Clojure on the JVM may be a better fit. +implements a subset of Clojure and is not as performant as compiled code. If your script is more than a one-off command that lasts only a few seconds, using Clojure on the JVM may be a better fit. Read more about the differences with Clojure [here](#differences-with-clojure). From 407cd3aeb17a355b3f3a198495e3224a7d09299f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:21:15 +0100 Subject: [PATCH 085/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb84a512..4885901f 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Non-goals: * Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them. Babashka uses [sci](https://github.com/borkdude/sci) for interpreting Clojure. Sci -implements a subset of Clojure and is not as performant as compiled code. If your script is more than a one-off command that lasts only a few seconds, using Clojure on the JVM may be a better fit. +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). From 926675d6cd1436e70aba21fddc82130083eefa27 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 28 Dec 2019 23:50:05 +0100 Subject: [PATCH 086/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4885901f..82c4daa5 100644 --- a/README.md +++ b/README.md @@ -438,7 +438,7 @@ Hello from gist script! 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 purposes and deployment. +convenient for debugging and deployment. Given the `deps.edn` from above: From 216317909a7a6e9a3650fa126b2340a2b82f467d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 00:15:07 +0100 Subject: [PATCH 087/169] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82c4daa5..6e3b1983 100644 --- a/README.md +++ b/README.md @@ -449,7 +449,8 @@ $ 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*) +(ns user (:require [my-gist-script])) +(apply my-gist-script/-main *command-line-args*) $ bb my-script.clj Hello from gist script! From 9f0c6df4db0aa126e3b93bad1f85c4b263e8fce2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 12:10:40 +0100 Subject: [PATCH 088/169] sci: fix bug when using a class in syntax-quote --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 92f2251f..885d7bed 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 92f2251fcc2ca795db05e78605e1c78bb8462884 +Subproject commit 885d7beddcd4ab77597ade6a9029a33ef7bb1233 From 294911a85abdfdb34e85f85e8ca8dc20f136abbf Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 12:15:36 +0100 Subject: [PATCH 089/169] v0.0.52 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 470d58fc..bdcd63ed 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.52-SNAPSHOT \ No newline at end of file +0.0.52 \ No newline at end of file From ffd235caab11cc74b31ce325217e37da4f334077 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 13:32:16 +0100 Subject: [PATCH 090/169] sci: require evaluates arguments --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 885d7bed..c5c70614 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 885d7beddcd4ab77597ade6a9029a33ef7bb1233 +Subproject commit c5c706146a9fbe9a162d9ac93a5055a6c87a8122 From 1ab393dfe24f03d8c70613596ec8b09bb57dc4bd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 13:32:41 +0100 Subject: [PATCH 091/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index ba4921ce..bdcd63ed 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.51 \ No newline at end of file +0.0.52 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index bdcd63ed..f62f53cc 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.52 \ No newline at end of file +0.0.53-SNAPSHOT \ No newline at end of file From b02cc48d904b9000a469fda25d7acb5a961421db Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 13:32:50 +0100 Subject: [PATCH 092/169] v0.0.53 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index f62f53cc..618e670a 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.53-SNAPSHOT \ No newline at end of file +0.0.53 \ No newline at end of file From 80a8e9b475064099ca9ca558a2847013e1984efc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 14:56:16 +0100 Subject: [PATCH 093/169] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e3b1983..fcfe0839 100644 --- a/README.md +++ b/README.md @@ -586,7 +586,11 @@ 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. +Clojure / babashka. + +#### [spartan.test](https://github.com/borkdude/spartan.test/) + +A minimal test framework compatible with babashka. #### [clj-http-lite](https://github.com/borkdude/clj-http-lite) From 283783bdd30f5c3e0a9a4299e7b240d372538992 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 15:50:31 +0100 Subject: [PATCH 094/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index bdcd63ed..618e670a 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.52 \ No newline at end of file +0.0.53 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 618e670a..4ccfd0bf 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.53 \ No newline at end of file +0.0.54-SNAPSHOT \ No newline at end of file From 16ca4098c80f9e68b041aa1a36a5ede16fde4e8c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 23:37:08 +0100 Subject: [PATCH 095/169] add io/resource --- src/babashka/impl/classpath.clj | 36 +++++++++++++++++++------------- src/babashka/main.clj | 17 ++++++++------- test/babashka/classpath_test.clj | 10 ++++++++- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/babashka/impl/classpath.clj b/src/babashka/impl/classpath.clj index a1846656..a90e5126 100644 --- a/src/babashka/impl/classpath.clj +++ b/src/babashka/impl/classpath.clj @@ -7,31 +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) - {:file (.getCanonicalPath f) - :source (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)) - {:file path - :source (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") @@ -40,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) - (:file (source-for-namespace l 'cheshire.core)) + (source-for-namespace l 'babashka.impl.cheshire nil) + (:file (source-for-namespace l 'cheshire.core nil)) ) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 7f34a985..8bdf6cc4 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -275,17 +275,20 @@ Everything after that is bound to *command-line-args*.")) (cp/loader classpath)) load-fn (when classpath (fn [{:keys [:namespace]}] - (let [res (cp/source-for-namespace loader namespace)] + (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 (assoc namespaces '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)) + :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} diff --git a/test/babashka/classpath_test.clj b/test/babashka/classpath_test.clj index 24048ade..dd20b197 100644 --- a/test/babashka/classpath_test.clj +++ b/test/babashka/classpath_test.clj @@ -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)))) @@ -41,3 +42,10 @@ (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))))) From 64844d9716df6a31041864988daad192a284b0b0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 29 Dec 2019 23:37:57 +0100 Subject: [PATCH 096/169] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fcfe0839..e4a4ec60 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ enumerated explicitly. - `sh` - `clojure.java.io` aliased as `io`: - `as-relative-path`, `as-url`, `copy`, `delete-file`, `file`, `input-stream`, - `make-parents`, `output-stream`, `reader`, `writer` + `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 From cecc86d42cefd4c2e43e4c095d39ce789d11d655 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 00:12:04 +0100 Subject: [PATCH 097/169] v0.0.54 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 4ccfd0bf..032ce9eb 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.54-SNAPSHOT \ No newline at end of file +0.0.54 \ No newline at end of file From 0a35971acac25e84cfb2a6fbbd8e8193345b76b2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 00:17:23 +0100 Subject: [PATCH 098/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 618e670a..032ce9eb 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.53 \ No newline at end of file +0.0.54 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 032ce9eb..e045dfe2 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.54 \ No newline at end of file +0.0.55-SNAPSHOT \ No newline at end of file From 8fc8571eb0d2c5da79c2c90179d7de076aa1db0a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 09:51:20 +0100 Subject: [PATCH 099/169] Icon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e4a4ec60..c96afc1a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + [![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master) [![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka) From 2ea28e41e16cb8f8d096808e648bbf0cddc08fda Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 10:29:54 +0100 Subject: [PATCH 100/169] Fix for #199 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index c5c70614..c2893be0 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit c5c706146a9fbe9a162d9ac93a5055a6c87a8122 +Subproject commit c2893be003b9311756f1ff6f6e2aa01e38e08fc2 From b6f484416b22c95880930aceb27168ea39ac2694 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 11:28:07 +0100 Subject: [PATCH 101/169] [#200] add shell/with-sh-dir and shell/with-sh-env --- README.md | 3 +- src/babashka/impl/clojure/java/io.clj | 1 + src/babashka/impl/clojure/java/shell.clj | 42 +++++++++++++++++++ src/babashka/main.clj | 4 +- .../babashka/impl/clojure/java/shell_test.clj | 17 ++++++++ 5 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/babashka/impl/clojure/java/shell.clj create mode 100644 test/babashka/impl/clojure/java/shell_test.clj diff --git a/README.md b/README.md index c96afc1a..71a3b1f6 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,7 @@ 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`, `as-url`, `copy`, `delete-file`, `file`, `input-stream`, `make-parents`, `output-stream`, `reader`, `resource`, `writer` diff --git a/src/babashka/impl/clojure/java/io.clj b/src/babashka/impl/clojure/java/io.clj index 88e7ec0c..5c26164b 100644 --- a/src/babashka/impl/clojure/java/io.clj +++ b/src/babashka/impl/clojure/java/io.clj @@ -1,4 +1,5 @@ (ns babashka.impl.clojure.java.io + {:no-doc true} (:require [clojure.java.io :as io])) (def io-namespace diff --git a/src/babashka/impl/clojure/java/shell.clj b/src/babashka/impl/clojure/java/shell.clj new file mode 100644 index 00000000..1d3aa429 --- /dev/null +++ b/src/babashka/impl/clojure/java/shell.clj @@ -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}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 8bdf6cc4..e6230073 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -7,6 +7,7 @@ [babashka.impl.classpath :as cp] [babashka.impl.clojure.core :refer [core-extras]] [babashka.impl.clojure.java.io :refer [io-namespace]] + [babashka.impl.clojure.java.shell :refer [shell-namespace]] [babashka.impl.clojure.stacktrace :refer [print-stack-trace]] [babashka.impl.csv :as csv] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] @@ -16,7 +17,6 @@ [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.core :as sci] @@ -218,7 +218,7 @@ Everything after that is bound to *command-line-args*.")) {'clojure.tools.cli tools-cli-namespace 'clojure.edn {'read edn/read 'read-string edn/read-string} - 'clojure.java.shell {'sh shell/sh} + '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?} diff --git a/test/babashka/impl/clojure/java/shell_test.clj b/test/babashka/impl/clojure/java/shell_test.clj new file mode 100644 index 00000000..0f1cd8db --- /dev/null +++ b/test/babashka/impl/clojure/java/shell_test.clj @@ -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"))) From 9bdaafbca977c5f283976313024b4abda0d725f3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 11:28:47 +0100 Subject: [PATCH 102/169] [#200] import IllegalArgumentException --- src/babashka/main.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index e6230073..f30e6463 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -299,6 +299,7 @@ Everything after that is bound to *command-line-args*.")) 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 From 24f4f7aafeb43bab8348e0336e20b3cec35e3da1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 11:33:23 +0100 Subject: [PATCH 103/169] [#200] add nio LinkOption --- reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + 2 files changed, 6 insertions(+) diff --git a/reflection.json b/reflection.json index 419388bc..69ce76bb 100644 --- a/reflection.json +++ b/reflection.json @@ -178,6 +178,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.nio.file.LinkOption", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.nio.file.NoSuchFileException", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 0eb5d5c2..8572315e 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -41,6 +41,7 @@ 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 From 30178101cf358f3d40ceeb6627fb4ec939558cbd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 11:39:57 +0100 Subject: [PATCH 104/169] v0.0.55 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index e045dfe2..4152b638 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.55-SNAPSHOT \ No newline at end of file +0.0.55 \ No newline at end of file From f8b32564586c6aabd3fe7abf20d60da8551de276 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 11:52:06 +0100 Subject: [PATCH 105/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- sci | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 032ce9eb..4152b638 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.54 \ No newline at end of file +0.0.55 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 4152b638..e7e8ceb9 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.55 \ No newline at end of file +0.0.56-SNAPSHOT \ No newline at end of file diff --git a/sci b/sci index c2893be0..d83a1af1 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit c2893be003b9311756f1ff6f6e2aa01e38e08fc2 +Subproject commit d83a1af1bad2d06581269eb042c837145f5cf17d From 426038c3ccaa6af62efb14ba8dd7aa743a6fe9dd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 13:38:05 +0100 Subject: [PATCH 106/169] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71a3b1f6..bc8a5ffc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A Clojure [babushka](https://en.wikipedia.org/wiki/Headscarf) for the grey areas of Bash.

From 2ed19cef999ab5fb71ef2ec135d8d7aac074cd30 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 18:06:02 +0100 Subject: [PATCH 107/169] Cleanup --- src/babashka/impl/clojure/stacktrace.clj | 9 +-------- src/babashka/impl/exceptions.clj | 8 +------- src/babashka/impl/socket_repl.clj | 1 - 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/babashka/impl/clojure/stacktrace.clj b/src/babashka/impl/clojure/stacktrace.clj index a220fd88..e2bbd8ff 100644 --- a/src/babashka/impl/clojure/stacktrace.clj +++ b/src/babashka/impl/clojure/stacktrace.clj @@ -78,11 +78,4 @@ (print-stack-trace tr n) (when-let [cause (.getCause tr)] (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)) + (recur cause n)))) \ No newline at end of file diff --git a/src/babashka/impl/exceptions.clj b/src/babashka/impl/exceptions.clj index 2d0dc9fd..b0c882ca 100644 --- a/src/babashka/impl/exceptions.clj +++ b/src/babashka/impl/exceptions.clj @@ -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) \ No newline at end of file diff --git a/src/babashka/impl/socket_repl.clj b/src/babashka/impl/socket_repl.clj index a18025b9..c18458d3 100644 --- a/src/babashka/impl/socket_repl.clj +++ b/src/babashka/impl/socket_repl.clj @@ -27,7 +27,6 @@ (server/stop-server)) (comment - (def sock (start-repl! "0.0.0.0:1666" {:env (atom {})})) @#'server/servers (stop-repl!) ) From e87d9aea82ad70908e207c5bdd54b5f1bff13b69 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 21:27:01 +0100 Subject: [PATCH 108/169] Add .carve_ignore --- .carve_ignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .carve_ignore diff --git a/.carve_ignore b/.carve_ignore new file mode 100644 index 00000000..060eba05 --- /dev/null +++ b/.carve_ignore @@ -0,0 +1,5 @@ +babashka.impl.classpath/->DirectoryResolver +babashka.impl.classpath/->JarFileResolver +babashka.impl.classpath/->Loader +babashka.impl.classes/generate-reflection-file +babashka.main/-main From 40b0d36871474977597b8868a35d1ea99bd5fcb1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 30 Dec 2019 23:13:12 +0100 Subject: [PATCH 109/169] .carve_ignore --- .carve_ignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.carve_ignore b/.carve_ignore index 060eba05..a68e40c6 100644 --- a/.carve_ignore +++ b/.carve_ignore @@ -3,3 +3,4 @@ babashka.impl.classpath/->JarFileResolver babashka.impl.classpath/->Loader babashka.impl.classes/generate-reflection-file babashka.main/-main +babashka.impl.clojure.stacktrace/root-cause From a9ac2cabbef471e098d09d69e8d7f0898f30038d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Dec 2019 14:13:22 +0100 Subject: [PATCH 110/169] Add java.net.Socket/Server --- .carve_ignore | 5 +---- reflection.json | 10 ++++++++++ sci | 2 +- src/babashka/impl/classes.clj | 2 ++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.carve_ignore b/.carve_ignore index a68e40c6..765c627a 100644 --- a/.carve_ignore +++ b/.carve_ignore @@ -1,6 +1,3 @@ -babashka.impl.classpath/->DirectoryResolver -babashka.impl.classpath/->JarFileResolver -babashka.impl.classpath/->Loader +babashka.impl.clojure.stacktrace/root-cause babashka.impl.classes/generate-reflection-file babashka.main/-main -babashka.impl.clojure.stacktrace/root-cause diff --git a/reflection.json b/reflection.json index 69ce76bb..d2af907a 100644 --- a/reflection.json +++ b/reflection.json @@ -143,6 +143,16 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.net.ServerSocket", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.net.Socket", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.net.URI", "allPublicMethods" : true, diff --git a/sci b/sci index d83a1af1..aa35523f 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit d83a1af1bad2d06581269eb042c837145f5cf17d +Subproject commit aa35523fd1be636c1f4ef214e9abf51e94df4952 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 8572315e..3d29286e 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -35,6 +35,8 @@ 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 From a5f26aca3fa1363882593a3c8651215f9b64950c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Dec 2019 14:18:00 +0100 Subject: [PATCH 111/169] Add test --- test/babashka/main_test.clj | 6 +++++- test/babashka/scripts/socket_server.bb | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/babashka/scripts/socket_server.bb diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 53f5d303..c1a5d79b 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -188,7 +188,11 @@ (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})"))))) + (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")] diff --git a/test/babashka/scripts/socket_server.bb b/test/babashka/scripts/socket_server.bb new file mode 100644 index 00000000..76467255 --- /dev/null +++ b/test/babashka/scripts/socket_server.bb @@ -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)) From a57d9f34bf33d3766e48d47d1c3476da6e54f411 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Dec 2019 14:23:54 +0100 Subject: [PATCH 112/169] v0.0.56 --- README.md | 25 ++----------------------- resources/BABASHKA_VERSION | 2 +- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index bc8a5ffc..1e7dba46 100644 --- a/README.md +++ b/README.md @@ -181,30 +181,9 @@ enumerated explicitly. - [`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 `reflection.json`. -- `ArithmeticException` -- `AssertionError` -- `Boolean` -- `Class` -- `Double` -- `Exception` -- `clojure.lang.ExceptionInfo` -- `Integer` -- `Math` -- `java.io.File` -- `java.nio.file.Files` -- `java.util.Base64` -- `java.util.regex.Pattern` -- `ProcessBuilder` (see [example](examples/process_builder.clj)). -- `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`: diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index e7e8ceb9..0f80e8fe 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.56-SNAPSHOT \ No newline at end of file +0.0.56 \ No newline at end of file From c4ee44e884ebad3148cec3cb3738b9fd06b38dd5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Dec 2019 14:30:32 +0100 Subject: [PATCH 113/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 4152b638..0f80e8fe 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.55 \ No newline at end of file +0.0.56 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 0f80e8fe..939bb6fa 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.56 \ No newline at end of file +0.0.57-SNAPSHOT \ No newline at end of file From 3a987c3f51c481bda05fa0ce11d158356f6ae3a4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 17:56:20 +0100 Subject: [PATCH 114/169] Fix problem with declare --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index aa35523f..4d8739f5 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit aa35523fd1be636c1f4ef214e9abf51e94df4952 +Subproject commit 4d8739f5a7cbb5302f2b3beb4a3afc0924b57dc0 From 2447f68502102787aa563d4b9891972fdfedd49f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 18:02:08 +0100 Subject: [PATCH 115/169] Add java.util.UUID --- reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + 2 files changed, 6 insertions(+) diff --git a/reflection.json b/reflection.json index d2af907a..791094e0 100644 --- a/reflection.json +++ b/reflection.json @@ -343,6 +343,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.util.UUID", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.util.concurrent.LinkedBlockingQueue", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 3d29286e..905ed123 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -75,6 +75,7 @@ java.util.Base64 java.util.Base64$Decoder java.util.Base64$Encoder + java.util.UUID java.util.zip.InflaterInputStream java.util.zip.DeflaterInputStream java.util.zip.GZIPInputStream From 0aaa40c035ee8fa9506ad1f67a33fe50f79df1d5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 20:06:26 +0100 Subject: [PATCH 116/169] sci: defonce --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 4d8739f5..d9c9a617 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 4d8739f5a7cbb5302f2b3beb4a3afc0924b57dc0 +Subproject commit d9c9a617669161344ef93d57e1d54851423b539a From 6d0531c26e518c6c482ab9b5f745212583d4905e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 20:11:45 +0100 Subject: [PATCH 117/169] Add clojure.lang.IOBj --- reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + 2 files changed, 6 insertions(+) diff --git a/reflection.json b/reflection.json index 791094e0..682304b2 100644 --- a/reflection.json +++ b/reflection.json @@ -8,6 +8,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "clojure.lang.IObj", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "clojure.lang.LineNumberingPushbackReader", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 905ed123..d6a53ebc 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -6,6 +6,7 @@ (def classes {:default-classes '[clojure.lang.Delay clojure.lang.ExceptionInfo + clojure.lang.IObj clojure.lang.LineNumberingPushbackReader java.io.BufferedReader java.io.BufferedWriter From 157ca481be0f93167dc8831c3c7ea031c02d1c61 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 20:34:32 +0100 Subject: [PATCH 118/169] Sci: add :name and :ns metadata to vars --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index d9c9a617..7ab259ad 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit d9c9a617669161344ef93d57e1d54851423b539a +Subproject commit 7ab259ad9ed0743a48f98fcf6fc25644f10c01f8 From ac789d07bc997eb6c4690fb28f2dc8e3af080c14 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 21:23:13 +0100 Subject: [PATCH 119/169] sci --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 7ab259ad..8f03065f 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 7ab259ad9ed0743a48f98fcf6fc25644f10c01f8 +Subproject commit 8f03065f3d7db66b0a853cef1b383dd9eafe3bd0 From 7fb02e32ed4c2641a3f598bccf97a26257e7de60 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 21:23:38 +0100 Subject: [PATCH 120/169] v0.0.57 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 939bb6fa..10efb6a5 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.57-SNAPSHOT \ No newline at end of file +0.0.57 \ No newline at end of file From fd833204f3be7fbe79120e33734db54d98eb5491 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 21:57:46 +0100 Subject: [PATCH 121/169] Release uberjar --- .circleci/config.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 16e2cbbb..9c65d74e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 + - store_artifacts: + path: /tmp/release + destination: release - save_cache: paths: - ~/.m2 From a9758b61704dce67535cb409738b598c0fc73288 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 22:04:25 +0100 Subject: [PATCH 122/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 0f80e8fe..10efb6a5 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.56 \ No newline at end of file +0.0.57 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 10efb6a5..50aec87a 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.57 \ No newline at end of file +0.0.58-SNAPSHOT \ No newline at end of file From 0362ecb7f652b40e230b2952696d5cfe8ad3a20a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 1 Jan 2020 23:27:25 +0100 Subject: [PATCH 123/169] Fix starting REPL when no expression is given --- README.md | 11 +++++++---- src/babashka/main.clj | 28 ++++++++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 1e7dba46..5b1605f8 100644 --- a/README.md +++ b/README.md @@ -131,25 +131,28 @@ You may also download a binary from [Github](https://github.com/borkdude/babashk ``` shellsession Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] - [ ( --classpath | -cp ) ] [ ( --main | -m ) ] - ( -e | -f | --repl | --socket-repl [:] ) - [ --uberscript ] [ arg* ] + [ ( --classpath | -cp ) ] [ --uberscript ] + [ ( --main | -m ) | -e | -f | + --repl | --socket-repl [:] ] + [ arg* ] Options: --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 Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. + -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. -m, --main Call the -main function from namespace with args. - --uberscript Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. --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. diff --git a/src/babashka/main.clj b/src/babashka/main.clj index f30e6463..4a3bda5a 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -134,9 +134,10 @@ (println (str "babashka v"(str/trim (slurp (io/resource "BABASHKA_VERSION")))))) (def usage-string "Usage: bb [ -i | -I ] [ -o | -O ] [ --stream ] [--verbose] - [ ( --classpath | -cp ) ] [ ( --main | -m ) ] - ( -e | -f | --repl | --socket-repl [:] ) - [ --uberscript ] [ arg* ]") + [ ( --classpath | -cp ) ] [ --uberscript ] + [ ( --main | -m ) | -e | -f | + --repl | --socket-repl [:] ] + [ arg* ]") (defn print-usage [] (println usage-string)) @@ -150,17 +151,19 @@ (println " --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 Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. + -e, --eval Evaluate an expression. -f, --file Evaluate a file. -cp, --classpath Classpath to use. -m, --main Call the -main function from namespace with args. - --uberscript Collect preloads, -e, -f and -m and all required namespaces from the classpath into a single executable file. --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. @@ -330,9 +333,13 @@ Everything after that is bound to *command-line-args*.")) file (try [(read-file file) nil] (catch Exception e (error-handler* e verbose?)))) - expression (str (when preloads - (str preloads "\n")) - expression) + exit-code + ;; 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} @@ -346,7 +353,7 @@ Everything after that is bound to *command-line-args*.")) [(print-help) 0] repl [(repl/start-repl! sci-ctx) 0] socket-repl [(start-socket-repl! socket-repl sci-ctx) 0] - expression + (not (str/blank? expression)) (try (loop [in (read-next *in*)] (let [_ (swap! env update-in [:namespaces 'user] @@ -371,6 +378,7 @@ Everything after that is bound to *command-line-args*.")) res))))) (catch Throwable e (error-handler* e verbose?))) + uberscript [nil 0] :else [(repl/start-repl! sci-ctx) 0])) 1))) t1 (System/currentTimeMillis)] @@ -381,8 +389,8 @@ Everything after that is bound to *command-line-args*.")) (spit uberscript-out "") ;; reset file (doseq [s @uberscript-sources] (spit uberscript-out s :append true)) - (spit uberscript-out expression :append true) - (spit uberscript-out file :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.")))) exit-code)) From b16e2812e047c89b5437926ceaf5e309e5f7aec8 Mon Sep 17 00:00:00 2001 From: Nate Sutton Date: Thu, 2 Jan 2020 02:29:26 -0600 Subject: [PATCH 124/169] Add clojure.stacktrace (#209) --- src/babashka/impl/clojure/stacktrace.clj | 9 ++++++++- src/babashka/main.clj | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/babashka/impl/clojure/stacktrace.clj b/src/babashka/impl/clojure/stacktrace.clj index e2bbd8ff..96fd9f32 100644 --- a/src/babashka/impl/clojure/stacktrace.clj +++ b/src/babashka/impl/clojure/stacktrace.clj @@ -78,4 +78,11 @@ (print-stack-trace tr n) (when-let [cause (.getCause tr)] (print "Caused by: " ) - (recur cause n)))) \ No newline at end of file + (recur cause n)))) + +(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}) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 4a3bda5a..30b86abe 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -8,7 +8,7 @@ [babashka.impl.clojure.core :refer [core-extras]] [babashka.impl.clojure.java.io :refer [io-namespace]] [babashka.impl.clojure.java.shell :refer [shell-namespace]] - [babashka.impl.clojure.stacktrace :refer [print-stack-trace]] + [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace print-stack-trace]] [babashka.impl.csv :as csv] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] [babashka.impl.repl :as repl] @@ -228,7 +228,8 @@ Everything after that is bound to *command-line-args*.")) 'clojure.java.io io-namespace 'clojure.core.async async-namespace 'clojure.data.csv csv/csv-namespace - 'cheshire.core cheshire-core-namespace}) + 'cheshire.core cheshire-core-namespace + 'clojure.stacktrace stacktrace-namespace}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control From 55e01c5b2c2fc9533cd78bfb70d7f95dbf2c7023 Mon Sep 17 00:00:00 2001 From: Nate Sutton Date: Thu, 2 Jan 2020 02:30:24 -0600 Subject: [PATCH 125/169] Add Throwable->map (#210) --- src/babashka/impl/clojure/core.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index a1a726df..a48bf53b 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -12,4 +12,5 @@ 'deliver deliver 'shutdown-agents shutdown-agents 'slurp slurp - 'spit spit}) + 'spit spit + 'Throwable->map Throwable->map}) From 95a9e91244613381e27f28a77e773522280eeb63 Mon Sep 17 00:00:00 2001 From: Nate Sutton Date: Thu, 2 Jan 2020 02:31:03 -0600 Subject: [PATCH 126/169] Add FileTime and TimeUnit for working with times on file attributes (#211) --- reflection.json | 10 ++++++++++ src/babashka/impl/classes.clj | 2 ++ 2 files changed, 12 insertions(+) diff --git a/reflection.json b/reflection.json index 682304b2..c21f45f5 100644 --- a/reflection.json +++ b/reflection.json @@ -223,6 +223,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.nio.file.attribute.FileTime", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.nio.file.attribute.PosixFilePermission", "allPublicMethods" : true, @@ -358,6 +363,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.util.concurrent.TimeUnit", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.util.regex.Pattern", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index d6a53ebc..636d24b2 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -50,6 +50,7 @@ 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 @@ -77,6 +78,7 @@ java.util.Base64$Decoder java.util.Base64$Encoder java.util.UUID + java.util.concurrent.TimeUnit java.util.zip.InflaterInputStream java.util.zip.DeflaterInputStream java.util.zip.GZIPInputStream From a04b7d00b43bb139cd17123154f00ca16aa0ebb8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 12:53:16 +0100 Subject: [PATCH 127/169] sci: allow metadata in defn --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 8f03065f..ee6ad73e 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 8f03065f3d7db66b0a853cef1b383dd9eafe3bd0 +Subproject commit ee6ad73e9adbcd7db468e3c6fb357d6ced76e8c8 From 978278768fce30d194fd5858f20f64f9d9769a0e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:39:22 +0100 Subject: [PATCH 128/169] Add a bunch of classes --- reflection.json | 20 ++++++++++++++++++++ sci | 2 +- src/babashka/impl/classes.clj | 4 ++++ src/babashka/impl/clojure/core.clj | 3 ++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/reflection.json b/reflection.json index c21f45f5..23a62826 100644 --- a/reflection.json +++ b/reflection.json @@ -8,6 +8,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "clojure.lang.IEditableCollection", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "clojure.lang.IObj", "allPublicMethods" : true, @@ -18,6 +23,16 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "clojure.lang.MapEntry", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "clojure.lang.PersistentQueue", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.io.BufferedReader", "allPublicMethods" : true, @@ -133,6 +148,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "java.lang.Throwable", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "java.lang.UNIXProcess", "allPublicMethods" : true, diff --git a/sci b/sci index ee6ad73e..3e4db8e6 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit ee6ad73e9adbcd7db468e3c6fb357d6ced76e8c8 +Subproject commit 3e4db8e6e59dd1c14fbe1ee840932ebdfdfaeeb9 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 636d24b2..2b9726cc 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -7,7 +7,10 @@ {:default-classes '[clojure.lang.Delay clojure.lang.ExceptionInfo clojure.lang.IObj + clojure.lang.IEditableCollection clojure.lang.LineNumberingPushbackReader + clojure.lang.MapEntry + clojure.lang.PersistentQueue java.io.BufferedReader java.io.BufferedWriter java.io.ByteArrayInputStream @@ -29,6 +32,7 @@ java.util.concurrent.LinkedBlockingQueue java.lang.String java.lang.System + java.lang.Throwable java.lang.Process java.lang.UNIXProcess java.lang.UNIXProcess$ProcessPipeOutputStream diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index a48bf53b..f3484565 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -13,4 +13,5 @@ 'shutdown-agents shutdown-agents 'slurp slurp 'spit spit - 'Throwable->map Throwable->map}) + 'Throwable->map Throwable->map + 'compare-and-set! compare-and-set!}) From 1d1863eafeaf2e35e4bb1131d4c1137ac0bf7ce9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:41:34 +0100 Subject: [PATCH 129/169] v0.0.58 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 50aec87a..5ec55f65 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.58-SNAPSHOT \ No newline at end of file +0.0.58 \ No newline at end of file From 0646b8f64cb4a6b67a185e787aa5c6eb89a66858 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:42:59 +0100 Subject: [PATCH 130/169] README: medley --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5b1605f8..05bdccec 100644 --- a/README.md +++ b/README.md @@ -573,6 +573,10 @@ Clojure / babashka. 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. + #### [clj-http-lite](https://github.com/borkdude/clj-http-lite) This fork does not depend on any other libraries. Example: From 391fea562b8de70d2d5b9ab947068626a8ce7be3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:44:24 +0100 Subject: [PATCH 131/169] README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05bdccec..5d776566 100644 --- a/README.md +++ b/README.md @@ -575,7 +575,8 @@ 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. +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) From d12d9b9f7086b5d898b3f6f9cb75f204208d7a61 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:53:35 +0100 Subject: [PATCH 132/169] README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5d776566..0c8d5df5 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ enumerated explicitly. - [`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. +- `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` From 277c69350338786810d5dfe71f3e7b7e8f07f592 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 13:56:21 +0100 Subject: [PATCH 133/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 10efb6a5..5ec55f65 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.57 \ No newline at end of file +0.0.58 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 5ec55f65..2e5e1c41 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.58 \ No newline at end of file +0.0.59-SNAPSHOT \ No newline at end of file From da66854f71290e957412af99210421d3c1aacbe0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 14:31:13 +0100 Subject: [PATCH 134/169] Alias --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 0c8d5df5..db2e4d2f 100644 --- a/README.md +++ b/README.md @@ -407,6 +407,8 @@ $ bb "(my-gist-script/-main)" Hello from gist script! ``` +### Deps.clj + Using the [deps.clj](https://github.com/borkdude/deps.clj/) script, you can also pass the classpath and main opts to `bb`: @@ -415,6 +417,16 @@ $ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}}" Hello from gist script! ``` +#### Alias + +Create an alias when you need to this often: + +``` shell +$ alias babashka='deps.clj -Scommand "rlwrap bb -cp {{classpath}} {{main-opts}}"' +$ babashka -A:my-script +Hello from gist script! +``` + ## Uberscript The `--uberscript` option collects the expressions in From 14db2bc0d6d5a2f7cf4ed003d05d3dc9a1356168 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 14:34:26 +0100 Subject: [PATCH 135/169] README --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index db2e4d2f..6838b309 100644 --- a/README.md +++ b/README.md @@ -409,17 +409,14 @@ Hello from gist script! ### Deps.clj -Using the [deps.clj](https://github.com/borkdude/deps.clj/) script, you can also -pass the classpath and main opts to `bb`: +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! ``` -#### Alias - -Create an alias when you need to this often: +Create this alias for brevity: ``` shell $ alias babashka='deps.clj -Scommand "rlwrap bb -cp {{classpath}} {{main-opts}}"' From 4800e80e5aa352e28f7ce2feccf45c379175c78d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 14:41:59 +0100 Subject: [PATCH 136/169] README --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6838b309..3400f128 100644 --- a/README.md +++ b/README.md @@ -416,12 +416,23 @@ $ deps.clj -A:my-script -Scommand "bb -cp {{classpath}} {{main-opts}}" Hello from gist script! ``` -Create this alias for brevity: +Create these aliases for brevity: ``` shell +$ alias bbk='deps.clj -Scommand "bb -cp {{classpath}} {{main-opts}}"' $ alias babashka='deps.clj -Scommand "rlwrap bb -cp {{classpath}} {{main-opts}}"' -$ babashka -A:my-script +$ 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 From 8a90eec5b4df60ceb03d038539031f0f3510979f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 14:45:41 +0100 Subject: [PATCH 137/169] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3400f128..25910e11 100644 --- a/README.md +++ b/README.md @@ -420,7 +420,7 @@ Create these aliases for brevity: ``` shell $ alias bbk='deps.clj -Scommand "bb -cp {{classpath}} {{main-opts}}"' -$ alias babashka='deps.clj -Scommand "rlwrap 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 From 28b873700de62283327bace4c7b8fcf07b42dc2a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 16:02:36 +0100 Subject: [PATCH 138/169] Add class for clj-http.lite --- reflection.json | 5 +++++ src/babashka/impl/classes.clj | 1 + 2 files changed, 6 insertions(+) diff --git a/reflection.json b/reflection.json index 23a62826..26f91f9b 100644 --- a/reflection.json +++ b/reflection.json @@ -413,6 +413,11 @@ "allPublicMethods" : true, "allPublicFields" : true, "allPublicConstructors" : true +}, { + "name" : "sun.net.www.http.PosterOutputStream", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true }, { "name" : "sun.net.www.protocol.http.HttpURLConnection", "allPublicMethods" : true, diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 2b9726cc..c276ee85 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -91,6 +91,7 @@ sun.net.www.protocol.https.HttpsURLConnectionImpl ;; needed fo clj-http.lite sun.net.www.protocol.http.HttpURLConnection ;; needed for clj.http.lite http calls sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; needed for clj-http.lite + sun.net.www.http.PosterOutputStream ;; needed for clj-http.lite ] :custom-classes {'java.lang.Thread {:allPublicConstructors true From 4233e52d8f60d325152350fec9be6aedf9499a71 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 16:02:53 +0100 Subject: [PATCH 139/169] v0.0.59 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 2e5e1c41..0634adbc 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.59-SNAPSHOT \ No newline at end of file +0.0.59 \ No newline at end of file From 85da23bf8201b019c80fd367e3020854a172363a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 2 Jan 2020 17:03:14 +0100 Subject: [PATCH 140/169] Version bump --- resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 5ec55f65..0634adbc 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.58 \ No newline at end of file +0.0.59 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 0634adbc..8990c51c 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.59 \ No newline at end of file +0.0.60-SNAPSHOT \ No newline at end of file From 32d9f5bcc5c1adae47de799b43407cdb2f0877ab Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 12:19:25 +0100 Subject: [PATCH 141/169] Add alter-var-root --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 3e4db8e6..6c83f835 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 3e4db8e6e59dd1c14fbe1ee840932ebdfdfaeeb9 +Subproject commit 6c83f8359b994772ed0a1d9cf21782cc0e70d891 From 0dd0482eb9b3b551a532b7da5edda9b2e9126f5f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 12:26:27 +0100 Subject: [PATCH 142/169] sci: switch to edamame/fn parsing --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 6c83f835..6535d143 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 6c83f8359b994772ed0a1d9cf21782cc0e70d891 +Subproject commit 6535d1437470dad90751278f17c262c3e9198c81 From 62f12e75eeb2ca8c8e1ad3671d9c783de44eb27f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 15:31:49 +0100 Subject: [PATCH 143/169] sci: use public alter-var-root --- project.clj | 1 + sci | 2 +- src/babashka/main.clj | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/project.clj b/project.clj index 07cdfa04..683045c8 100644 --- a/project.clj +++ b/project.clj @@ -12,6 +12,7 @@ :dependencies [[org.clojure/clojure "1.10.1"] [org.clojure/tools.reader "1.3.2"] [borkdude/edamame "0.0.10-alpha.2"] + [borkdude/graal.locking "0.0.2"] [org.clojure/core.async "0.4.500"] [org.clojure/tools.cli "0.4.2"] [org.clojure/data.csv "0.1.4"] diff --git a/sci b/sci index 6535d143..a6286ce3 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 6535d1437470dad90751278f17c262c3e9198c81 +Subproject commit a6286ce315452137057d40c1cdc127091a6429a3 diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 30b86abe..a1318f4c 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -25,9 +25,9 @@ [sci.impl.interpreter :refer [eval-string*]]) (:gen-class)) -(sci.impl.vars/bindRoot sci/in *in*) -(sci.impl.vars/bindRoot sci/out *out*) -(sci.impl.vars/bindRoot sci/err *err*) +(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: From 5e2c2a7ba0d391f0e0b53804bf59a8fc78d798fe Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:04:29 +0100 Subject: [PATCH 144/169] Add locking --- .circleci/config.yml | 6 +- .gitignore | 1 + reflection.json | 554 ------------------------- reflection.json.bak | 185 --------- script/clj_http_lite_test | 15 + src/babashka/impl/classes.clj | 351 +++++++++------- src/babashka/impl/clojure/core.clj | 7 +- src/babashka/main.clj | 1 + test/babashka/http_connection_test.clj | 21 + 9 files changed, 239 insertions(+), 902 deletions(-) delete mode 100644 reflection.json delete mode 100644 reflection.json.bak create mode 100755 script/clj_http_lite_test create mode 100644 test/babashka/http_connection_test.clj diff --git a/.circleci/config.yml b/.circleci/config.yml index 9c65d74e..3cfc1471 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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: @@ -52,7 +52,7 @@ jobs: mkdir -p /tmp/release lein do clean, uberjar VERSION=$(cat resources/BABASHKA_VERSION) - cp target/babashka-$VERSION-standalone.jar /tmp/release + cp target/babashka-$VERSION-linux-standalone.jar /tmp/release - store_artifacts: path: /tmp/release destination: release @@ -115,6 +115,7 @@ jobs: name: Run tests command: | script/test + script/clj_http_lite_test # - run: # name: Performance report # command: | @@ -178,6 +179,7 @@ jobs: name: Run tests command: | script/test + script/clj_http_lite_test # - run: # name: Performance report # command: | diff --git a/.gitignore b/.gitignore index a96a9d65..ba4d6ce4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ pom.xml.asc !test-resources/babashka/src_for_classpath_test/foo.jar .cpcache deps.edn +reflection.json diff --git a/reflection.json b/reflection.json deleted file mode 100644 index 26f91f9b..00000000 --- a/reflection.json +++ /dev/null @@ -1,554 +0,0 @@ -[ { - "name" : "clojure.lang.Delay", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.ExceptionInfo", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.IEditableCollection", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.IObj", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.LineNumberingPushbackReader", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.MapEntry", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "clojure.lang.PersistentQueue", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.BufferedReader", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.BufferedWriter", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.ByteArrayInputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.ByteArrayOutputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.File", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.IOException", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.InputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.io.OutputStream", - "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.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.lang.Class", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Double", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Exception", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Integer", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Math", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Process", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.ProcessBuilder", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.ProcessBuilder$Redirect", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.String", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.System", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.Throwable", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.UNIXProcess", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.lang.UNIXProcess$ProcessPipeOutputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.HttpURLConnection", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.ServerSocket", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.Socket", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.URI", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.URLDecoder", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.URLEncoder", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.net.UnknownHostException", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : 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.LinkOption", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.NoSuchFileException", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.Path", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.Paths", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.StandardCopyOption", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.attribute.FileAttribute", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.nio.file.attribute.FileTime", - "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.time.Clock", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.DateTimeException", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.DayOfWeek", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.Duration", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.Instant", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.LocalDate", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.LocalDateTime", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.LocalTime", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.Month", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.MonthDay", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.OffsetDateTime", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.OffsetTime", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.Period", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.Year", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.YearMonth", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.ZoneId", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.ZoneOffset", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.ZonedDateTime", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.format.DateTimeFormatter", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.time.temporal.TemporalAccessor", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.Base64", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.Base64$Decoder", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.Base64$Encoder", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.UUID", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.concurrent.LinkedBlockingQueue", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.concurrent.TimeUnit", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.regex.Pattern", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.zip.DeflaterInputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.zip.GZIPInputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.zip.GZIPOutputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "java.util.zip.InflaterInputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.net.www.http.PosterOutputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.net.www.protocol.http.HttpURLConnection", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.net.www.protocol.http.HttpURLConnection$HttpInputStream", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.net.www.protocol.https.HttpsURLConnectionImpl", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "name" : "sun.nio.fs.UnixPath", - "allPublicMethods" : true, - "allPublicFields" : true, - "allPublicConstructors" : true -}, { - "allPublicConstructors" : true, - "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" - } ], - "name" : "java.lang.Thread" -}, { - "allPublicConstructors" : true, - "allPublicFields" : true, - "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" - }, { - "name" : "toExternalForm" - }, { - "name" : "toString" - }, { - "name" : "toURI" - } ], - "name" : "java.net.URL" -} ] \ No newline at end of file diff --git a/reflection.json.bak b/reflection.json.bak deleted file mode 100644 index a41c3fcd..00000000 --- a/reflection.json.bak +++ /dev/null @@ -1,185 +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 - } -] diff --git a/script/clj_http_lite_test b/script/clj_http_lite_test new file mode 100755 index 00000000..c1b260f6 --- /dev/null +++ b/script/clj_http_lite_test @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +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\"))) +" diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index c276ee85..12a5a291 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -1,164 +1,186 @@ (ns babashka.impl.classes {:no-doc true} (:require - [cheshire.core :as json])) + [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 - {:default-classes '[clojure.lang.Delay - clojure.lang.ExceptionInfo - clojure.lang.IObj - clojure.lang.IEditableCollection - clojure.lang.LineNumberingPushbackReader - clojure.lang.MapEntry - clojure.lang.PersistentQueue - 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.String - java.lang.System - java.lang.Throwable - java.lang.Process - java.lang.UNIXProcess - java.lang.UNIXProcess$ProcessPipeOutputStream - 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.UUID - java.util.concurrent.TimeUnit - java.util.zip.InflaterInputStream - java.util.zip.DeflaterInputStream - java.util.zip.GZIPInputStream - java.util.zip.GZIPOutputStream - sun.nio.fs.UnixPath ;; included because of permission check - sun.net.www.protocol.https.HttpsURLConnectionImpl ;; needed fo clj-http.lite - sun.net.www.protocol.http.HttpURLConnection ;; needed for clj.http.lite http calls - sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; needed for clj-http.lite - sun.net.www.http.PosterOutputStream ;; needed for clj-http.lite - ] - :custom-classes {'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"}]}}}) + (cond-> + '{: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 [] + :methods [borkdude.graal.LockFix ;; support for locking + sun.net.www.http.PosterOutputStream ;; support for clj-http-lite + sun.net.www.protocol.https.HttpsURLConnectionImpl ;; support for clj-http-lite + sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; support for clj-http-lite + ] + :fields [clojure.lang.PersistentQueue] + :instance-checks [clojure.lang.Delay + clojure.lang.ExceptionInfo + clojure.lang.IObj + clojure.lang.IEditableCollection + clojure.lang.LineNumberingPushbackReader + clojure.lang.MapEntry] + :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"}]}}} + unix-like? (-> + (update :methods conj 'sun.nio.fs.UnixPath) + (update :all conj + 'java.lang.UNIXProcess + 'java.lang.UNIXProcess$ProcessPipeOutputStream)))) (defmacro gen-class-map [] - (let [classes (concat (:default-classes classes) - (keys (:custom-classes classes)))] + (let [classes (concat (:all classes) + (keys (:custom classes)) + (:constructors classes) + (:methods classes) + (:fields classes) + (:instance-checks classes))] (apply hash-map (for [c classes c [(list 'quote c) c]] @@ -166,22 +188,31 @@ (def class-map (gen-class-map)) -#_(defn sym->class-name [sym] - (-> sym str (str/replace "$" "."))) - (defn generate-reflection-file "Generate reflection.json file" [& args] - (let [entries (vec (for [c (sort (:default-classes classes)) + (let [entries (vec (for [c (sort (:all classes)) :let [class-name (str c)]] {:name class-name :allPublicMethods true :allPublicFields true :allPublicConstructors true})) - custom-entries (for [[c v] (:custom-classes classes) + 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 custom-entries)] + all-entries (concat entries constructors methods fields custom-entries)] (spit (or (first args) "reflection.json") (json/generate-string all-entries {:pretty true})))) diff --git a/src/babashka/impl/clojure/core.clj b/src/babashka/impl/clojure/core.clj index f3484565..d3a69ee4 100644 --- a/src/babashka/impl/clojure/core.clj +++ b/src/babashka/impl/clojure/core.clj @@ -1,6 +1,10 @@ (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 @@ -10,6 +14,7 @@ 'send-off send-off 'promise promise 'deliver deliver + 'locking (with-meta locking* {:sci/macro true}) 'shutdown-agents shutdown-agents 'slurp slurp 'spit spit diff --git a/src/babashka/main.clj b/src/babashka/main.clj index a1318f4c..70b54f29 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -307,6 +307,7 @@ Everything after that is bound to *command-line-args*.")) 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 diff --git a/test/babashka/http_connection_test.clj b/test/babashka/http_connection_test.clj new file mode 100644 index 00000000..40f3a7c2 --- /dev/null +++ b/test/babashka/http_connection_test.clj @@ -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 (.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))) +"))))) From a14119c5d3ed5b69fafabdc9785e6f34c26330b2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:06:11 +0100 Subject: [PATCH 145/169] README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 25910e11..8d1eb4d3 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ on [CHANGES.md](CHANGES.md) for a list of breaking changes. ``` shellsession $ ls | bb -i '*input*' -["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"] +["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "resources" "script" "src" "target" "test"] $ ls | bb -i '(count *input*)' 12 @@ -75,8 +75,8 @@ $ bb '(filterv :foo *input*)' <<< '[{:foo 1} {:bar 2}]' $ bb '(#(+ %1 %2 %3) 1 2 *input*)' <<< 3 6 -$ ls | bb -i '(filterv #(re-find #"reflection" %) *input*)' -["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 '*input*' @@ -185,7 +185,7 @@ enumerated explicitly. - [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv` - [`cheshire.core`](https://github.com/dakrone/cheshire) aliased as `json` -A selection of java classes are available, see `reflection.json`. +A selection of java classes are available, see `babashka/impl/classes.clj`. Babashka supports `import`: `(import clojure.lang.ExceptionInfo)`. From a5c2f62d386553267e4e67d504571b9670ae69af Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:07:19 +0100 Subject: [PATCH 146/169] Fix java build --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3cfc1471..03e77c4f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,7 @@ jobs: mkdir -p /tmp/release lein do clean, uberjar VERSION=$(cat resources/BABASHKA_VERSION) - cp target/babashka-$VERSION-linux-standalone.jar /tmp/release + cp target/babashka-$VERSION-standalone.jar /tmp/release/babashka-$VERSION-linux-standalone.jar - store_artifacts: path: /tmp/release destination: release From 1d3cd975bac85861ce75108b50914b43e06b5dd3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:21:09 +0100 Subject: [PATCH 147/169] Add constructors for Delay and MapEntry --- src/babashka/impl/classes.clj | 11 +++++------ test/babashka/main_test.clj | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 12a5a291..d20af400 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -91,19 +91,18 @@ java.util.zip.GZIPInputStream java.util.zip.GZIPOutputStream ] - :constructors [] + :constructors [clojure.lang.Delay + clojure.lang.MapEntry + clojure.lang.LineNumberingPushbackReader] :methods [borkdude.graal.LockFix ;; support for locking sun.net.www.http.PosterOutputStream ;; support for clj-http-lite sun.net.www.protocol.https.HttpsURLConnectionImpl ;; support for clj-http-lite sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; support for clj-http-lite ] :fields [clojure.lang.PersistentQueue] - :instance-checks [clojure.lang.Delay - clojure.lang.ExceptionInfo + :instance-checks [clojure.lang.ExceptionInfo clojure.lang.IObj - clojure.lang.IEditableCollection - clojure.lang.LineNumberingPushbackReader - clojure.lang.MapEntry] + clojure.lang.IEditableCollection] :custom {clojure.lang.LineNumberingPushbackReader {:allPublicConstructors true :allPublicMethods true} java.lang.Thread diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index c1a5d79b..8088e878 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -328,6 +328,12 @@ (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 From 8f005224ca6cbed77a80240580f9da24bd7d67b4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:28:17 +0100 Subject: [PATCH 148/169] Dev note --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d1eb4d3..e14e5bae 100644 --- a/README.md +++ b/README.md @@ -655,7 +655,16 @@ 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`. -### Generate reflection.json file +### 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 From e425b835be1f26dae69c5783cb19de046a75162f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sat, 4 Jan 2020 20:30:43 +0100 Subject: [PATCH 149/169] v0.0.60 --- resources/BABASHKA_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 8990c51c..67ccd586 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.60-SNAPSHOT \ No newline at end of file +0.0.60 \ No newline at end of file From 2bab1d826b4f5a4f423ba4feff45a59a33cf8871 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Jan 2020 00:20:58 +0100 Subject: [PATCH 150/169] sci: issue 222 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index a6286ce3..7fcbf1b2 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit a6286ce315452137057d40c1cdc127091a6429a3 +Subproject commit 7fcbf1b20375ebdf38da8f2885ba652dc6c63c04 From 193bbc2888bce4c0134ed0bf66b1648d66298100 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Jan 2020 17:45:25 +0100 Subject: [PATCH 151/169] sci: preserve tag in let (#216) --- project.clj | 1 + resources/BABASHKA_RELEASED_VERSION | 2 +- resources/BABASHKA_VERSION | 2 +- sci | 2 +- src/babashka/impl/classes.clj | 6 +----- test/babashka/http_connection_test.clj | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/project.clj b/project.clj index 683045c8..afc5c1e4 100644 --- a/project.clj +++ b/project.clj @@ -13,6 +13,7 @@ [org.clojure/tools.reader "1.3.2"] [borkdude/edamame "0.0.10-alpha.2"] [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"] diff --git a/resources/BABASHKA_RELEASED_VERSION b/resources/BABASHKA_RELEASED_VERSION index 0634adbc..67ccd586 100644 --- a/resources/BABASHKA_RELEASED_VERSION +++ b/resources/BABASHKA_RELEASED_VERSION @@ -1 +1 @@ -0.0.59 \ No newline at end of file +0.0.60 \ No newline at end of file diff --git a/resources/BABASHKA_VERSION b/resources/BABASHKA_VERSION index 67ccd586..e2e3d510 100644 --- a/resources/BABASHKA_VERSION +++ b/resources/BABASHKA_VERSION @@ -1 +1 @@ -0.0.60 \ No newline at end of file +0.0.61-SNAPSHOT \ No newline at end of file diff --git a/sci b/sci index 7fcbf1b2..74e58536 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 7fcbf1b20375ebdf38da8f2885ba652dc6c63c04 +Subproject commit 74e58536995367d358225f5a71ebb12928dc3b96 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index d20af400..851786ad 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -89,15 +89,11 @@ java.util.zip.InflaterInputStream java.util.zip.DeflaterInputStream java.util.zip.GZIPInputStream - java.util.zip.GZIPOutputStream - ] + java.util.zip.GZIPOutputStream] :constructors [clojure.lang.Delay clojure.lang.MapEntry clojure.lang.LineNumberingPushbackReader] :methods [borkdude.graal.LockFix ;; support for locking - sun.net.www.http.PosterOutputStream ;; support for clj-http-lite - sun.net.www.protocol.https.HttpsURLConnectionImpl ;; support for clj-http-lite - sun.net.www.protocol.http.HttpURLConnection$HttpInputStream ;; support for clj-http-lite ] :fields [clojure.lang.PersistentQueue] :instance-checks [clojure.lang.ExceptionInfo diff --git a/test/babashka/http_connection_test.clj b/test/babashka/http_connection_test.clj index 40f3a7c2..ec78fa12 100644 --- a/test/babashka/http_connection_test.clj +++ b/test/babashka/http_connection_test.clj @@ -10,7 +10,7 @@ (deftest open-connection-test (is (= "\"1\"" (str/trim (bb "-e" " (require '[cheshire.core :as json]) -(let [conn (.openConnection (java.net.URL. \"https://postman-echo.com/get?foo=1\"))] +(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) From ab6ea2de081384b202ce0d804630d64429975e23 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Jan 2020 19:01:55 +0100 Subject: [PATCH 152/169] add demunge --- src/babashka/impl/clojure/main.clj | 6 ++++++ src/babashka/main.clj | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/babashka/impl/clojure/main.clj b/src/babashka/impl/clojure/main.clj index 43e2b434..3d8a9f2f 100644 --- a/src/babashka/impl/clojure/main.clj +++ b/src/babashka/impl/clojure/main.clj @@ -17,6 +17,12 @@ babashka.impl.clojure.main (: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 that often need to be set!: *ns* *warn-on-reflection* *math-context* diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 70b54f29..ff8071f4 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -8,6 +8,7 @@ [babashka.impl.clojure.core :refer [core-extras]] [babashka.impl.clojure.java.io :refer [io-namespace]] [babashka.impl.clojure.java.shell :refer [shell-namespace]] + [babashka.impl.clojure.main :refer [demunge]] [babashka.impl.clojure.stacktrace :refer [stacktrace-namespace print-stack-trace]] [babashka.impl.csv :as csv] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] @@ -20,9 +21,9 @@ [clojure.string :as str] [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] - [sci.impl.interpreter :refer [eval-string*]]) + [sci.impl.vars :as vars]) (:gen-class)) (sci/alter-var-root sci/in (constantly *in*)) @@ -229,7 +230,9 @@ Everything after that is bound to *command-line-args*.")) 'clojure.core.async async-namespace 'clojure.data.csv csv/csv-namespace 'cheshire.core cheshire-core-namespace - 'clojure.stacktrace stacktrace-namespace}) + 'clojure.stacktrace stacktrace-namespace + 'clojure.main {'demunge demunge} + 'clojure.repl {'demunge demunge}}) (def bindings {'java.lang.System/exit exit ;; override exit, so we have more control From 82d4096dfbaca5253f51b46de2a1c4500b883346 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Sun, 5 Jan 2020 22:11:44 +0100 Subject: [PATCH 153/169] sci: add any? and inst? --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 74e58536..e5c34aa2 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 74e58536995367d358225f5a71ebb12928dc3b96 +Subproject commit e5c34aa292c1d96f7ed41ae01af3fd61d78bd66e From f267adfe799f80dc7a2d00818d8e22d57f0002b6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Jan 2020 13:22:43 +0100 Subject: [PATCH 154/169] Add http server example --- README.md | 6 +++++ examples/http_server.clj | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 examples/http_server.clj diff --git a/README.md b/README.md index e14e5bae..8570bb57 100644 --- a/README.md +++ b/README.md @@ -832,6 +832,12 @@ jet --pretty > deps.edn 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 diff --git a/examples/http_server.clj b/examples/http_server.clj new file mode 100755 index 00000000..0c045993 --- /dev/null +++ b/examples/http_server.clj @@ -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" + (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 "\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))) From 15db79ac80f0773aaa5df28012bed6b67ac49fc0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Jan 2020 20:40:02 +0100 Subject: [PATCH 155/169] Sci: remove eval mark after evaluation --- .gitignore | 1 - deps.edn | 12 ++++++++++++ sci | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 deps.edn diff --git a/.gitignore b/.gitignore index ba4d6ce4..d8a7040d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +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 diff --git a/deps.edn b/deps.edn new file mode 100644 index 00000000..ac224ccc --- /dev/null +++ b/deps.edn @@ -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.2"}, + 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"]}}} diff --git a/sci b/sci index e5c34aa2..1b4b6b51 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit e5c34aa292c1d96f7ed41ae01af3fd61d78bd66e +Subproject commit 1b4b6b51e8e290f51064cbc7951f593fa6c4eb5f From 42e84d9dacbabb5e685f1d22915e576cce0c8453 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Jan 2020 22:58:25 +0100 Subject: [PATCH 156/169] Bump edamame --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index ac224ccc..f2992f2e 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {: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.2"}, + borkdude/edamame {:mvn/version "0.0.10-alpha.3"}, 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"}, diff --git a/project.clj b/project.clj index afc5c1e4..a566edb0 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,7 @@ :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.3"] [borkdude/graal.locking "0.0.2"] [borkdude/sci.impl.reflector "0.0.1"] [org.clojure/core.async "0.4.500"] diff --git a/sci b/sci index 1b4b6b51..517cd781 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 1b4b6b51e8e290f51064cbc7951f593fa6c4eb5f +Subproject commit 517cd781afa9ee25d7401974a935b29e6f89a0d8 From aaf78a093d0cba2da9286f00a532c9711d4fbdb9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 6 Jan 2020 23:50:46 +0100 Subject: [PATCH 157/169] Bump edamame once more --- deps.edn | 2 +- project.clj | 2 +- sci | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index f2992f2e..e3051185 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {: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.3"}, + 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"}, diff --git a/project.clj b/project.clj index a566edb0..8da51448 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,7 @@ :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.3"] + [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"] diff --git a/sci b/sci index 517cd781..91bd3054 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 517cd781afa9ee25d7401974a935b29e6f89a0d8 +Subproject commit 91bd3054d0d01fb719b0e2b3659bdc32e39063fa From 51af94f70bca2c0e8f3fd0bd573c862649fb7731 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 09:20:42 +0100 Subject: [PATCH 158/169] Add deps.clj test --- .circleci/config.yml | 2 ++ script/deps_clj_test | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100755 script/deps_clj_test diff --git a/.circleci/config.yml b/.circleci/config.yml index 03e77c4f..f7b43c3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -116,6 +116,7 @@ jobs: command: | script/test script/clj_http_lite_test + script/deps_clj_test # - run: # name: Performance report # command: | @@ -180,6 +181,7 @@ jobs: command: | script/test script/clj_http_lite_test + script/deps_clj_test # - run: # name: Performance report # command: | diff --git a/script/deps_clj_test b/script/deps_clj_test new file mode 100755 index 00000000..41407727 --- /dev/null +++ b/script/deps_clj_test @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +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 From 2c7a9386213bde5993caefc6ef3d50ea83f84548 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 09:33:37 +0100 Subject: [PATCH 159/169] Add lib tests --- .circleci/config.yml | 6 ++---- script/{ => lib_tests}/clj_http_lite_test | 2 ++ script/{ => lib_tests}/deps_clj_test | 3 +++ script/lib_tests/spartan_spec_test | 11 +++++++++++ script/run_lib_tests | 7 +++++++ 5 files changed, 25 insertions(+), 4 deletions(-) rename script/{ => lib_tests}/clj_http_lite_test (96%) rename script/{ => lib_tests}/deps_clj_test (90%) create mode 100755 script/lib_tests/spartan_spec_test create mode 100755 script/run_lib_tests diff --git a/.circleci/config.yml b/.circleci/config.yml index f7b43c3b..5a88c60b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -115,8 +115,7 @@ jobs: name: Run tests command: | script/test - script/clj_http_lite_test - script/deps_clj_test + script/run_lib_tests # - run: # name: Performance report # command: | @@ -180,8 +179,7 @@ jobs: name: Run tests command: | script/test - script/clj_http_lite_test - script/deps_clj_test + script/run_lib_tests # - run: # name: Performance report # command: | diff --git a/script/clj_http_lite_test b/script/lib_tests/clj_http_lite_test similarity index 96% rename from script/clj_http_lite_test rename to script/lib_tests/clj_http_lite_test index c1b260f6..d9c0cf43 100755 --- a/script/clj_http_lite_test +++ b/script/lib_tests/clj_http_lite_test @@ -1,5 +1,7 @@ #!/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 " diff --git a/script/deps_clj_test b/script/lib_tests/deps_clj_test similarity index 90% rename from script/deps_clj_test rename to script/lib_tests/deps_clj_test index 41407727..29d78dc3 100755 --- a/script/deps_clj_test +++ b/script/lib_tests/deps_clj_test @@ -1,6 +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 + diff --git a/script/lib_tests/spartan_spec_test b/script/lib_tests/spartan_spec_test new file mode 100755 index 00000000..5afe02ef --- /dev/null +++ b/script/lib_tests/spartan_spec_test @@ -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\"]) +" diff --git a/script/run_lib_tests b/script/run_lib_tests new file mode 100755 index 00000000..9e107365 --- /dev/null +++ b/script/run_lib_tests @@ -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 From 56f21874b75d81a073ba709ffa557101c757e82d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 10:57:59 +0100 Subject: [PATCH 160/169] Sci: add macroexpand --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 91bd3054..1245cf09 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 91bd3054d0d01fb719b0e2b3659bdc32e39063fa +Subproject commit 1245cf096b320a034b5aa3c17aa4528798cb372c From 115045c481154093d5af0b73cbb6529d1f3a16b6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 11:19:30 +0100 Subject: [PATCH 161/169] Sci: macroexpand --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 1245cf09..4772116a 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 1245cf096b320a034b5aa3c17aa4528798cb372c +Subproject commit 4772116ac6c3b615b786d0a019364fa654bfedf5 From fcc28657bc2a63371b1a5695c02261297f82e05f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 12:58:27 +0100 Subject: [PATCH 162/169] Publish artifact links to Slack --- .circleci/config.yml | 8 ++++++++ .circleci/script/publish_artifact | 5 +++++ 2 files changed, 13 insertions(+) create mode 100755 .circleci/script/publish_artifact diff --git a/.circleci/config.yml b/.circleci/config.yml index 5a88c60b..49f267e8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -132,6 +132,10 @@ jobs: - store_artifacts: path: /tmp/release destination: release + - run: + name: Publish artifact link to Slack + command: | + .circleci/script/publish_artifact mac: macos: xcode: "9.0" @@ -196,6 +200,10 @@ jobs: - store_artifacts: path: /tmp/release destination: release + - run: + name: Publish artifact link to Slack + command: | + .circleci/script/publish_artifact deploy: docker: - image: circleci/clojure:lein-2.8.1 diff --git a/.circleci/script/publish_artifact b/.circleci/script/publish_artifact new file mode 100755 index 00000000..d5931a50 --- /dev/null +++ b/.circleci/script/publish_artifact @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +channel="#babashka_circleci_builds" +text="[$BABASHKA_PLATFORM - $CIRCLE_BRANCH@$CIRCLE_SHA1]: https://$CIRCLE_BUILD_NUM-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.61-SNAPSHOT-$BABASHKA_PLATFORM-amd64.zip" +curl -X POST -H "Content-Type: application/json" -d '{"username":"borkdude", "channel":'\""$channel\""', "text":'"\"$text\""'}' $SLACK_HOOK_URL From ece81e0a99f0e0a54dce5e7806633b57e233a1f3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 15:44:59 +0100 Subject: [PATCH 163/169] Sci: improve macroexpand and add .. macro --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 4772116a..d9e6d739 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 4772116ac6c3b615b786d0a019364fa654bfedf5 +Subproject commit d9e6d7396374631731a9cc7b11dedb41281e867d From bf481b76d1a64cf2da53e6d858b389b8c59549bb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 16:38:54 +0100 Subject: [PATCH 164/169] Rewrite bash script in bb --- .circleci/config.yml | 4 ++-- .circleci/script/publish_artifact | 5 ----- .circleci/script/publish_artifact.clj | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) delete mode 100755 .circleci/script/publish_artifact create mode 100755 .circleci/script/publish_artifact.clj diff --git a/.circleci/config.yml b/.circleci/config.yml index 49f267e8..c30939cd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -135,7 +135,7 @@ jobs: - run: name: Publish artifact link to Slack command: | - .circleci/script/publish_artifact + ./bb .circleci/script/publish_artifact mac: macos: xcode: "9.0" @@ -203,7 +203,7 @@ jobs: - run: name: Publish artifact link to Slack command: | - .circleci/script/publish_artifact + ./bb .circleci/script/publish_artifact deploy: docker: - image: circleci/clojure:lein-2.8.1 diff --git a/.circleci/script/publish_artifact b/.circleci/script/publish_artifact deleted file mode 100755 index d5931a50..00000000 --- a/.circleci/script/publish_artifact +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -channel="#babashka_circleci_builds" -text="[$BABASHKA_PLATFORM - $CIRCLE_BRANCH@$CIRCLE_SHA1]: https://$CIRCLE_BUILD_NUM-201467090-gh.circle-artifacts.com/0/release/babashka-0.0.61-SNAPSHOT-$BABASHKA_PLATFORM-amd64.zip" -curl -X POST -H "Content-Type: application/json" -d '{"username":"borkdude", "channel":'\""$channel\""', "text":'"\"$text\""'}' $SLACK_HOOK_URL diff --git a/.circleci/script/publish_artifact.clj b/.circleci/script/publish_artifact.clj new file mode 100755 index 00000000..cb55f321 --- /dev/null +++ b/.circleci/script/publish_artifact.clj @@ -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))) From c3830511944cf9bc83689ace2457bcc92ea438d4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 7 Jan 2020 16:43:48 +0100 Subject: [PATCH 165/169] Fix --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c30939cd..78cf06cb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -135,7 +135,7 @@ jobs: - run: name: Publish artifact link to Slack command: | - ./bb .circleci/script/publish_artifact + ./bb .circleci/script/publish_artifact.clj mac: macos: xcode: "9.0" @@ -203,7 +203,7 @@ jobs: - run: name: Publish artifact link to Slack command: | - ./bb .circleci/script/publish_artifact + ./bb .circleci/script/publish_artifact.clj deploy: docker: - image: circleci/clojure:lein-2.8.1 From 6633d8b674a3785cbec600d2e30d70de19da1ce0 Mon Sep 17 00:00:00 2001 From: Peter Nagy Date: Wed, 8 Jan 2020 08:45:41 +0100 Subject: [PATCH 166/169] fixes clj-http-lite example in README (#226) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8570bb57..ffb50eaa 100644 --- a/README.md +++ b/README.md @@ -604,7 +604,7 @@ babashka. Requires `bb` >= v0.0.58. This fork does not depend on any other libraries. Example: ``` shell -$ export BABASHKA_CLASSPATH="$(clojure -Sdeps '{:deps {limit-break {:git/url "https://github.com/borkdude/clj-http-lite" :sha "f44ebe45446f0f44f2b73761d102af3da6d0a13e"}}}' -Spath)" +$ 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 From 2b0cb6fb1cf2f86a9bdf22dd6b954a35ec1be21f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Jan 2020 11:48:40 +0100 Subject: [PATCH 167/169] Remove Unix-specific classes (#227) --- .circleci/config.yml | 2 +- sci | 2 +- src/babashka/impl/classes.clj | 336 +++++++++++++++++----------------- test/babashka/main_test.clj | 6 +- 4 files changed, 174 insertions(+), 172 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 78cf06cb..c25a8ea2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,7 @@ jobs: mkdir -p /tmp/release lein do clean, uberjar VERSION=$(cat resources/BABASHKA_VERSION) - cp target/babashka-$VERSION-standalone.jar /tmp/release/babashka-$VERSION-linux-standalone.jar + cp target/babashka-$VERSION-standalone.jar /tmp/release/babashka-$VERSION-standalone.jar - store_artifacts: path: /tmp/release destination: release diff --git a/sci b/sci index d9e6d739..1374d2a3 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit d9e6d7396374631731a9cc7b11dedb41281e867d +Subproject commit 1374d2a37b64e3d2216349345ff930b1154e39b3 diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 851786ad..415c2e41 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -2,172 +2,166 @@ {:no-doc true} (:require [cheshire.core :as json] - [clojure.string :as str])) + #_[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 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 - (cond-> - '{: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"}]}}} - unix-like? (-> - (update :methods conj 'sun.nio.fs.UnixPath) - (update :all conj - 'java.lang.UNIXProcess - 'java.lang.UNIXProcess$ProcessPipeOutputStream)))) + '{: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) @@ -175,11 +169,17 @@ (:constructors classes) (:methods classes) (:fields classes) - (:instance-checks classes))] - (apply hash-map - (for [c classes - c [(list 'quote c) c]] - c)))) + (: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)) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 8088e878..0e90881b 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -169,6 +169,8 @@ (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)") @@ -281,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 From 673e9eed22c8db5d661161f2bda0c3e430eee488 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Jan 2020 16:55:16 +0100 Subject: [PATCH 168/169] sci: issue 232 --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 1374d2a3..2c102fab 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 1374d2a37b64e3d2216349345ff930b1154e39b3 +Subproject commit 2c102fab1149678ee69c1bdd96d8b1303bdc2e92 From 303ca9e825d76a4a45bc4240a59139d342c13964 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Jan 2020 17:22:59 +0100 Subject: [PATCH 169/169] sci issue 217: support list in case --- sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sci b/sci index 2c102fab..57b584ba 160000 --- a/sci +++ b/sci @@ -1 +1 @@ -Subproject commit 2c102fab1149678ee69c1bdd96d8b1303bdc2e92 +Subproject commit 57b584ba0a6a1f74a887d350463a700976dd37d8