Fork me on GitHub
#babashka
<
2020-08-20
>
borkdude09:08:23

$ cat /tmp/foo.clj





(defn foo []
  (+ 1 2 :foo))

(foo)
$ bb -f /tmp/foo.clj
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.lang.Number [at /tmp/foo.clj, line 7, column 3]
     3:
     4:
     5:
     6: (defn foo []
     7:   (+ 1 2 :foo))
          ^--- clojure.lang.Keyword cannot be cast to java.lang.Number [at /tmp/foo.clj, line 7, column 3]
     8:
     9: (foo)
Stacktrace:
   clojure.core/+ - <built-in>
   user/foo - /tmp/foo.clj:7:3
   user/foo - /tmp/foo.clj:6:1
   user - /tmp/foo.clj:9:1
Some polishing needed, but getting there.

😍 6
borkdude12:08:51

Some things to consider: - Should we only show the context with the error message and not the first line which contains the same error message? - Should we show the stacktrace by default or write it to a temp .edn file like clojure does?

lread13:08:50

The formatting is helpful and reminds me of what I saw from shadow-cljs warnings when testing rewrite-cljc against shadow-cljs.

lread13:08:43

I’ll try to dig up a sample if you are not already familiar.

borkdude13:08:07

Not familiar, so example welcome

lread13:08:47

Did not quickly find one on web, so turned on deprecation warnings for rewrite-cljc here’s a sample:

borkdude13:08:19

Thanks for sharing

borkdude13:08:30

So shadow does use coloring to make some things stand out. We can do that I guess.

borkdude13:08:48

Not sure if all terminals support this and if we should detect this, etc.

lread13:08:50

Ya, the coloring is interesting. Also inspired by shadow-cljs, might consider not repeating filename and line number in contextual message?

7:   (+ 1 2 :foo))
          ^--- clojure.lang.Keyword cannot be cast to java.lang.Number [at /tmp/foo.clj, line 7, column 3]
could be:
7:   (+ 1 2 :foo))
          ^--- clojure.lang.Keyword cannot be cast to java.lang.Number

lread13:08:41

I’ll try triggering a stack trace under shadow-cljs and see if it can offer inspiration there as well…

lread13:08:42

Hmm… not sure… I’m only using shadow-cljs to to run unit tests… maybe somebody more familiar with shadow-cljs can give a stack trace example.

lread13:08:38

But… now I’m also now reminded of figwheel-main. I think it does formatting of errors?

borkdude13:08:00

Yes, that was the initial inspiration, jeroenvandijk did the initial implementation based on that

lread13:08:05

As to your question: > - Should we only show the context with the error message and not the first line which contains the same error message?

lread13:08:03

I think the first line is just saying pretty much the same thing as the contextual message and does not add value.

lread13:08:10

And as to: > - Should we show the stacktrace by default or write it to a temp .edn file like clojure does?

lread13:08:41

I’m not sure. If the stack trace is huge and scrolls the summary off the screen, that would make the details hide the summary. But you had the idea of maybe only showing the first 5 and last 5 items, so maybe that would solve that? But what if you really need the full trace? I was initially annoyed by the change in clojure to write the stack trace to an edn file, but then got over it quickly when I realized they also added the --report option.

borkdude13:08:33

If you need the full trace you can do --verbose

lread13:08:42

Right… I see, tx.

lread13:08:21

So I guess the question is, is the contextual message typically enough info, and the stack trace typically noise?

borkdude14:08:05

We can also make each stack element contextual

borkdude14:08:25

But maybe that's a bit too much

borkdude14:08:49

I think it's useful to know where things started and ended. The part in the middle is usually not that interesting

lread14:08:17

That’s my experience as well.

lread14:08:02

Am I right in thinking-out-loud that: for clojure one goal is to make it easy for tooling to take advantage of and use data it spits out to provide a good experience for the user. This would also be true for babashka as well, but babashka being a scripting tool, is used stand-alone and should provide some of the niceties that clojure does not want to concern itself with. Hence your contextual message.

borkdude14:08:13

One thing I'd like to do different with babashka is spit out file locations that you can click on (either in terminal or emacs) so it will point you to the right file.

borkdude14:08:26

I've personally never used error information as data from clojure shell invocations

borkdude14:08:28

The current stack trace has this

borkdude14:08:09

I guess we can have both: spit out data and show useful information. We can do the data bit later if people want it, but I don't expect it.

lread14:08:17

Clickable paths is a thoughtful feature.

lread14:08:36

As I ramble away, I’m thinking what I would like would be terse by default (I think the context message would be all I need usually), with an option to be less terse (maybe adds your 5/5 stack trace with context for each item), and then an option to be fully verbose (full stack trace with context for every item). I wonder what other folks think? (hint hint others! simple_smile). And maybe I would not really need the middle option. Terse or fully verbose might do.

hugod14:08:13

With stack traces I most often use the first few lines up to the first project specific frame that isn’t some sort of helper function.

borkdude14:08:06

First few lines: is that beginning at the point of error? e.g.:

(defn foo [] (/ 1 0)) (foo)
Will now print:
java.lang.ArithmeticException: Divide by zero [at <expr>, line 1, column 14]
     1: (defn foo [] (/ 1 0)) (foo)
                     ^--- Divide by zero [at <expr>, line 1, column 14]
Stacktrace:
   clojure.core// - <built-in>
   user/foo - <expr>:1:14
   user/foo - <expr>:1:1
   user - <expr>:1:23

hugod14:08:51

Wow, that looks good! the stacktrace seems superfluous in that example. By first I meant deepest. The highest level frames are usually only interesting in multi-threaded code. In general errors are either implementation errors or errors in how something is being called. Both tend to lie in project specific code, so a stack trace that doesn’t show a project specific frame is usually not very helpful.

borkdude14:08:30

Here's another example with a bigger stacktrace:

$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {borkdude/spartan.spec {:git/url "" :sha "ff7317d67ec15f188afb856d37090e5c9509374e"}}}')
$ bb -e "(defn f [_] (/ 1 0)) (require '[spartan.spec :as s]) (s/explain (s/cat :x int? :y f) [1 #{:foo}])"
java.lang.ArithmeticException: Divide by zero [at <expr>, line 1, column 13]
     1: (defn f [_] (/ 1 0)) (require '[spartan.spec :as s]) (s/explain (s/cat :x int? :y f) [1 #{:foo}])
                    ^--- Divide by zero [at <expr>, line 1, column 13]
Stacktrace:
   clojure.core// - <built-in>
   user - <expr>:1:13
   spartan.spec/dt local: pred - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:604:5
   spartan.spec/dt - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:611:16
   spartan.spec/dt - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:602:8
...
   spartan.spec/explain-out - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:279:16
   spartan.spec/explain-out - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:269:1
   spartan.spec/explain - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:279:3
   spartan.spec/explain - /Users/borkdude/.gitlibs/libs/borkdude/spartan.spec/ff7317d67ec15f188afb856d37090e5c9509374e/src/spartan/spec.clj:276:1
   user - <expr>:1:54

borkdude14:08:11

I guess it needs a bit of testing with various scripts to see what's best

borkdude14:08:48

If you want to test it out, there's binaries in #babashka_circleci_builds from the issue-508-free-st branch

isak14:08:12

Does babashka support multi-threading (in one script)?

isak14:08:42

😎 nice

borkdude14:08:17

It also has core.async

borkdude14:08:43

And you can use future or even (Thread. ...)

isak14:08:56

wow, that sounds perfect, thanks 🙂

isak14:08:30

On the JVM, jdbc requires a native dependency (`sqljdbc_auth.dll`) to connect to SQL Server via "Integrated Authentication". Does that sound like something can work with Babashka?

borkdude14:08:11

@isak Loading native libraries works, also in GraalVM, but that needs to be built into babashka or a babashka pod. We have babashka pods for several database flavors: https://github.com/babashka/babashka-sql-pods. As of now there is no SQL Server pod.

borkdude14:08:53

So contributing a pod or feature flag to babashka yourself would probably be the only way right now.

isak14:08:40

Ok, sounds good

grahamcarlyle16:08:16

Is there anything like https://github.com/vadimdemedes/ink for building babashka based cli apps?

borkdude16:08:51

Not that I know of

grahamcarlyle16:08:37

the only thing that i've come across so far for the jvm is https://picocli.info/

borkdude16:08:43

@grahamcarlyle That doesn't do react-like rendering as far as I know? There is also react-blessed for node. I've gotten it to work with Reagent once.

grahamcarlyle16:08:20

i wasn't so much interested in ink for its react like api, though thats nice, i was interested in any libs that would support developing simple cli apps in babashka

borkdude16:08:54

Do you mean command line parsing?

borkdude16:08:10

Babashka comes with clojure.tools.cli as a library. There is also https://github.com/nubank/docopt.clj#babashka.

borkdude16:08:54

There's also work on cli-matic to make it compatible: https://github.com/l3nz/cli-matic/issues/113

grahamcarlyle16:08:06

More for coloured text rendering, and simple layout, basic input, progress bars etc.

borkdude17:08:17

@grahamcarlyle

$ export BABASHKA_CLASSPATH=$(clojure -Spath -Sdeps '{:deps {io.aviso/pretty {:mvn/version "RELEASE"}}}')
$ bb -e "(require '[io.aviso.ansi :as ansi]) (println (str \"The following text will be \" ansi/bold-red-font \"bold and red\" ansi/reset-font \".\"))"

borkdude17:08:44

@grahamcarlyle This ansi code is also pretty useful, for clearing the screen: https://twitter.com/borkdude/status/1278357459363602432

borkdude17:08:23

Here's an overview that should be usable to build some of this stuff maybe: http://ascii-table.com/ansi-escape-sequences-vt-100.php

👍 3