[#382] add optional support for hsqldb

This commit is contained in:
Michiel Borkent 2020-04-26 13:10:30 +02:00
parent 9b631a2427
commit ac24abbbfb
12 changed files with 297 additions and 85 deletions

View file

@ -771,6 +771,8 @@ handling of the SIGPIPE. This can be done by setting
- [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
## [Building babashka](doc/build.md)
## [Developing Babashka](doc/dev.md)
## Related projects

View file

@ -13,7 +13,8 @@
clj-commons/clj-yaml {:mvn/version "0.7.1"}
com.cognitect/transit-clj {:mvn/version "1.0.324"}
seancorfield/next.jdbc {:mvn/version "1.0.424"}
org.postgresql/postgresql {:mvn/version "42.2.12"}}
org.postgresql/postgresql {:mvn/version "42.2.12"}
org.hsqldb/hsqldb {:mvn/version "2.4.0"}}
:aliases {:main
{:main-opts ["-m" "babashka.main"]}
:profile

77
doc/build.md Normal file
View file

@ -0,0 +1,77 @@
# Building babashka
## Prerequisites
- Install [lein](https://leiningen.org/) for producing uberjars
- Download [GraalVM](https://www.graalvm.org/downloads/). Currently we use *java8-19.3.1*.
- Set `$GRAALVM_HOME` to the GraalVM distribution directory. On macOS this can look like:
``` shell
export GRAALVM_HOME=~/Downloads/graalvm-ce-java8-19.3.1/Contents/Home
```
On linux:
``` shell
export GRAALVM_HOME=~/Downloads/graalvm-ce-java8-19.3.1
```
On Windows:
```
set GRAALVM_HOME=C:\Users\IEUser\Downloads\graalvm-ce-java8-19.3.1
```
## Clone repository
NOTE: the babashka repository contains submodules. You need to use the
`--recursive` flag to clone these submodules along with the main repo.
``` shellsession
$ git clone https://github.com/borkdude/babashka --recursive
```
To update later on:
``` shellsession
$ git submodule update --recursive
```
## Build
Run the `compile` script:
``` shell
$ script/compile
```
To configure maximum heap size you can use:
```
$ BABASHKA_XMX="-J-Xmx4g" script/compile
```
## Windows
To compile on Windows you need to check out the `windows` branch:
``` shell
$ git checkout windows
```
The compile script for Windows is `script/compile.bat`.
## Optional features
### HyperSQL
To compile babashka with `HyperSQL`/`hsqldb` support, set
`BABASHKA_FEATURE_HSQLDB` to `true`:
``` shell
$ BABASHKA_FEATURE_HSQLDB=true script/compile
```
If you think this feature should be enabled in the distributed version of `bb`,
vote with a thumbs up on [this](https://github.com/borkdude/babashka/issues/382)
issue.

View file

@ -45,17 +45,7 @@ Test the native version:
## Build
To build this project, set `$GRAALVM_HOME` to the GraalVM distribution directory. Currently we are using GraalVM JDK8.
Then run:
$ script/compile
To tweak maximum heap size:
```
$ BABASHKA_XMX="-J-Xmx4g" script/compile
```
See [build.md](build.md).
## Binary size

View file

@ -272,3 +272,25 @@ A script to retrieve the version from a `pom.xml` file. See
Show frequencies of messages by user in Whatsapp group chats.
See [examples/whatsapp_frequencies.clj](examples/whatsapp_frequencies.clj)
### Find unused vars
[This](../examples/hsqldb_unused_vars.clj) script invokes clj-kondo, stores
returned data in an in memory HSQLDB database and prints the result of a query
which finds unused vars.
``` shell
$ bb examples/hsqldb_unused_vars.clj src
| :VARS/NS | :VARS/NAME | :VARS/FILENAME | :VARS/ROW | :VARS/COL |
|----------------------------+--------------------------+------------------------------------+-----------+-----------|
| babashka.impl.bencode.core | read-netstring | src/babashka/impl/bencode/core.clj | 162 | 1 |
| babashka.impl.bencode.core | write-netstring | src/babashka/impl/bencode/core.clj | 201 | 1 |
| babashka.impl.classes | generate-reflection-file | src/babashka/impl/classes.clj | 230 | 1 |
| babashka.impl.classpath | ->DirectoryResolver | src/babashka/impl/classpath.clj | 12 | 1 |
| babashka.impl.classpath | ->JarFileResolver | src/babashka/impl/classpath.clj | 37 | 1 |
| babashka.impl.classpath | ->Loader | src/babashka/impl/classpath.clj | 47 | 1 |
| babashka.impl.clojure.test | file-position | src/babashka/impl/clojure/test.clj | 286 | 1 |
| babashka.impl.nrepl-server | stop-server! | src/babashka/impl/nrepl_server.clj | 179 | 1 |
| babashka.main | -main | src/babashka/main.clj | 485 | 1 |
```

85
examples/hsqldb_unused_vars.clj Executable file
View file

@ -0,0 +1,85 @@
#!/usr/bin/env bb
;; $ examples/hsqldb_unused_vars.clj src
;; | :VARS/NS | :VARS/NAME | :VARS/FILENAME | :VARS/ROW | :VARS/COL |
;; |----------------------------+--------------------------+------------------------------------+-----------+-----------|
;; | babashka.impl.bencode.core | read-netstring | src/babashka/impl/bencode/core.clj | 162 | 1 |
;; | babashka.impl.bencode.core | write-netstring | src/babashka/impl/bencode/core.clj | 201 | 1 |
;; | babashka.impl.classes | generate-reflection-file | src/babashka/impl/classes.clj | 230 | 1 |
;; | babashka.impl.classpath | ->DirectoryResolver | src/babashka/impl/classpath.clj | 12 | 1 |
;; | babashka.impl.classpath | ->JarFileResolver | src/babashka/impl/classpath.clj | 37 | 1 |
;; | babashka.impl.classpath | ->Loader | src/babashka/impl/classpath.clj | 47 | 1 |
;; | babashka.impl.clojure.test | file-position | src/babashka/impl/clojure/test.clj | 286 | 1 |
;; | babashka.impl.nrepl-server | stop-server! | src/babashka/impl/nrepl_server.clj | 179 | 1 |
;; | babashka.main | -main | src/babashka/main.clj | 485 | 1 |
(ns hsqldb-unused-vars
(:require
[clojure.edn :as edn]
[clojure.java.shell :refer [sh]]
[clojure.pprint :refer [print-table]]
[next.jdbc :as jdbc]
[next.jdbc.sql :as sql]))
(def db "jdbc:hsqldb:mem:testdb;sql.syntax_mys=true")
(defn query [q]
(jdbc/execute! db [q]))
(defn create-db! []
(query "create table vars (
ns text
, name text
, filename text
, row int
, col int )")
(query "create table var_usages (
\"from\" text
, \"to\" text
, name text
, filename text
, row int
, col int )"))
(defn parse-int [^String x]
(when x
(Integer. x)))
(defn insert-vars! [var-definitions]
(sql/insert-multi! db :vars [:ns :name :filename :row :col]
(map (juxt (comp str :ns)
(comp str :name)
:filename
(comp parse-int :row)
(comp parse-int :col))
var-definitions)))
(defn insert-var-usages! [var-usages]
(sql/insert-multi! db :var_usages ["\"from\"" "\"to\"" :name :filename :row :col]
(map (juxt (comp str :from)
(comp str :to)
(comp str :name)
:filename
(comp parse-int :row)
(comp parse-int :col))
var-usages)))
(defn analysis->db [paths]
(let [out (:out (apply sh "clj-kondo"
"--config" "{:output {:analysis true :format :edn}}"
"--lint" paths))
analysis (:analysis (edn/read-string out))
{:keys [:var-definitions :var-usages]} analysis]
(insert-vars! var-definitions)
(insert-var-usages! var-usages)))
(create-db!)
(analysis->db *command-line-args*)
(def unused-vars "
select distinct * from vars v
where (v.ns, v.name) not in
(select vu.\"to\", vu.name from var_usages vu)")
(print-table (query unused-vars))

View file

@ -26,7 +26,8 @@
[com.cognitect/transit-clj "1.0.324"]
[seancorfield/next.jdbc "1.0.424"]
[org.postgresql/postgresql "42.2.12"]]
:profiles {:test {:dependencies [[clj-commons/conch "0.9.2"]
:profiles {:feature/hsqldb {:dependencies [[org.hsqldb/hsqldb "2.4.0"]]}
:test {:dependencies [[clj-commons/conch "0.9.2"]
[com.clojure-goes-fast/clj-async-profiler "0.4.1"]]}
:uberjar {:global-vars {*assert* false}
:jvm-opts ["-Dclojure.compiler.direct-linking=true"

View file

@ -20,9 +20,17 @@ export JAVA_HOME=$GRAALVM_HOME
SVM_JAR=$(find "$GRAALVM_HOME" | grep svm.jar)
$GRAALVM_HOME/bin/javac -cp "$SVM_JAR" resources/CutOffCoreServicesDependencies.java
BABASHKA_LEIN_PROFILES=""
if [ "$BABASHKA_FEATURE_HSQLDB" = "true" ]
then
BABASHKA_LEIN_PROFILES="+feature/hsqldb"
fi
if [ -z "$BABASHKA_JAR" ]; then
lein with-profiles +reflection do run
lein do clean, uberjar
lein with-profiles "+reflection,$BABASHKA_LEIN_PROFILES" do run
lein with-profiles "$BABASHKA_LEIN_PROFILES" do clean, uberjar
BABASHKA_JAR=${BABASHKA_JAR:-"target/babashka-$BABASHKA_VERSION-standalone.jar"}
fi
@ -53,6 +61,10 @@ if [ "$BABASHKA_STATIC" = "true" ]; then
args+=("--static")
fi
if [ "$BABASHKA_FEATURE_HSQLDB" = "true" ]; then
args+=("-H:IncludeResources=org/hsqldb/.*\.properties", "-H:IncludeResources=org/hsqldb/.*\.sql")
fi
$GRAALVM_HOME/bin/native-image "${args[@]}"
if [ ! -z "$(command -v lein)" ]; then

View file

@ -1,8 +1,86 @@
(ns babashka.impl.classes
{:no-doc true}
(:require
[babashka.impl.features :as features]
[cheshire.core :as json]))
(def custom-map
(cond->
`{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"}]}
com.sun.xml.internal.stream.XMLInputFactoryImpl
{:methods [{:name "<init>" :parameterTypes []}]}
com.sun.xml.internal.stream.XMLOutputFactoryImpl
{:methods [{:name "<init>" :parameterTypes []}]}}
features/hsqldb? (assoc `org.hsqldb.dbinfo.DatabaseInformationFull
{:methods [{:name "<init>"
:parameterTypes ["org.hsqldb.Database"]}]}
`java.util.ResourceBundle
{:methods [{:name "getBundle"
:parameterTypes ["java.lang.String","java.util.Locale","java.lang.ClassLoader"]}]})))
(def classes
`{:all [clojure.lang.ExceptionInfo
java.io.BufferedReader
@ -108,7 +186,7 @@
java.util.zip.GZIPOutputStream
org.yaml.snakeyaml.error.YAMLException
~(symbol "[B")
]
~@(when features/hsqldb? [`org.hsqldb.jdbcDriver])]
:constructors [clojure.lang.Delay
clojure.lang.MapEntry
clojure.lang.LineNumberingPushbackReader
@ -120,74 +198,7 @@
:fields [clojure.lang.PersistentQueue]
:instance-checks [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"}]}
com.sun.xml.internal.stream.XMLInputFactoryImpl
{:methods [{:name "<init>" :parameterTypes []}]}
com.sun.xml.internal.stream.XMLOutputFactoryImpl
{:methods [{:name "<init>" :parameterTypes []}]}}})
:custom ~custom-map})
(defmacro gen-class-map []
(let [classes (concat (:all classes)

View file

@ -0,0 +1,4 @@
(ns babashka.impl.features
{:no-doc true})
(def hsqldb? (= "true" (System/getenv "BABASHKA_FEATURE_HSQLDB")))

View file

@ -1,6 +1,7 @@
(ns babashka.impl.jdbc
{:no-doc true}
(:require [next.jdbc :as njdbc]
[next.jdbc.sql :as sql]
[sci.impl.namespaces :refer [copy-var]]
[sci.impl.vars :as vars]))
@ -29,3 +30,8 @@
'transact (copy-var njdbc/transact next-ns)
'with-transaction (with-meta with-transaction
{:sci/macro true})})
(def sns (vars/->SciNamespace 'next.jdbc.sql nil))
(def next-sql-namespace
{'insert-multi! (copy-var sql/insert-multi! sns)})

View file

@ -295,7 +295,8 @@ Everything after that is bound to *command-line-args*."))
'babashka.curl curl-namespace
'cognitect.transit transit-namespace
'bencode.core bencode-namespace
'next.jdbc jdbc/njdbc-namespace})
'next.jdbc jdbc/njdbc-namespace
'next.jdbc.sql jdbc/next-sql-namespace})
(def bindings
{'java.lang.System/exit exit ;; override exit, so we have more control