Fork me on GitHub
#babashka
<
2021-12-03
>
Cnly09:12:00

Hi, I’m playing with clojure.core/read and its https://clojuredocs.org/clojure.core/read says the stream must be an instance of java.io.PushbackReader or some derivee. While this is true in clojure, in babashka 0.6.7 it seems I have to use clojure.lang.LineNumberingPushbackReader instead. If I just use the former, I get

Message:  No implementation of method: :get-line-number of protocol: #'clojure.tools.reader.reader-types/IndexingReader
found for class: java.io.PushbackReader
Any idea what the problem is? Here’s the script which prints out all forms read from the file specified as a command line argument:
(ns hello
  (:require [ :as io])
  (:import [ PushbackReader]))

(println (let [reader (PushbackReader. (io/reader (first *command-line-args*)))]
   (binding [*read-eval* false]
     (take-while #(not (identical? ::eof %)) (repeatedly #(read {:eof ::eof} reader))))))

borkdude09:12:48

@UUKPL2T9C I didn't know that clojure.core/read worked with any pushbackreader, but in bb clojure.core/read is implemented using edamame which currently requires an indexedreader

borkdude09:12:01

This should probably be fixed, so feel free to post an issue

borkdude09:12:25

you have to wrap the PushbackReader in LineNumberingPushbackReader indeed

Cnly09:12:56

Thanks, let me open that later

mmz09:12:09

For mac users who want to customise their menubar: Here are 2 relatively simple XBAR plugin examples I coded ... in Babashka of course! :star-struck: https://github.com/mmzsource/xbar-plugins

borkdude09:12:32

That looks very useful, I should try xbar

mmz09:12:26

I looks like Apple is not so developer friendly in terms of backwards compatibility ... the menu items that provided this functionality for me break every new big MacOS update. So I decided to put one abstraction layer in between (xbar) and just write these simple plugins myself 😄

borkdude09:12:01

does xbar also work on linux and Windows? that would be even more awesome for cross platform

mmz09:12:12

don't think so 😬

mmz09:12:55

Most of my tools are cross platform because of emacs 🤓 But not these ones :man-shrugging::skin-tone-3: Interesting interface by the way 🙂

ordnungswidrig10:12:39

Nice, I use xbar and bb is a good implementation choice!

babashka 1
tbrooke13:12:44

I am using a javascript (npm) program that has an elaborate but complex CLI - I want to send data from my Clojure App to the ClI as input and retrieve the data that is output — Should I be using nbb or Babashka?

borkdude13:12:59

does the npm program support a programmatic API as well?

borkdude13:12:10

then you could use it directly from nbb

borkdude13:12:19

if you need to shell out, then you might as well use bb

tbrooke14:12:08

It does have a programmable API but it is pure javascript - building objects, promises, etc - so I guess babashka is my best bet — this is for a quick and dirty test until I figure out how to do the full interop — Other than streamlining the npm based API is ther anything Babashka can help me with in regard to CLI calls from a Clojure (not Clojurescript) app?

borkdude14:12:09

Do you mean, from a JVM Clojure app you want to call the npm app?

borkdude14:12:38

I recommend using babashka.process for this: https://github.com/babashka/process

borkdude14:12:48

This library works with the JVM as well and is also available within babashka

tbrooke14:12:31

Wow thanks I will check it out - yes it is a JVM app — Juxt’s site to be exact

borkdude14:12:35

You need to get the string output from this app? Then it would look something like:

(require '[babashka.process :as process :refer [process]])
(-> (process "node your-thing" {:out :string}) deref :out)

tbrooke14:12:10

perfect - this is what I was experimenting with and process will be much better: (defn run-cicero-cli "Simple proof of concept for parse from command line -- pretty slow" [contract] (let [cta (str local-dir contract)] (bu/sh "cicero" "parse" cta :out-enc "UTF-8")))

borkdude14:12:39

what is bu/sh?

tbrooke14:12:28

Sorry it is a command line library Jacob O’Bryant wrote for Biff: (defn sh "Runs a shell command. Returns the output if successful; otherwise, throws an exception." [& args] (let [result (apply shell/sh args)] (if (= 0 (:exit result)) (:out result) (throw (ex-info (:err result) result)))))

tbrooke14:12:19

trouble is it returns everything including some irrelevant stuff that has to be parsed out

borkdude14:12:55

yeah, you could also just use clojure.java.shell if you need string output btw

tbrooke14:12:22

Any drawbacks or advantages of babashka.process over clojure.java.shell?

borkdude15:12:51

babashka.process supports more use cases

tbrooke15:12:20

Perfect - Thanks - and since I already have the JVM going it should be fairly fast — I’ll give you a report when I get things running

tbrooke14:12:04

@U04V15CAJ I know this is not totally a Babashka question but I get a file not found error when trying to run ciceor in the process: Execution error (IOException) at java.lang.ProcessImpl/forkAndExec (ProcessImpl.java:-2). ; error=2, No such file or directory My speculation is that the process shell is not the same as my system shell and doesn’t have access to npm - I did find this in Googling https://stackoverflow.com/questions/40503074/how-to-run-npm-command-in-java-using-process-builder What do you think?

borkdude14:12:10

can you show me the full incantation?

borkdude14:12:19

and on which OS are you?

borkdude15:12:14

and the full invocation?

tbrooke15:12:20

Cicero is my NPM program (def ci '[cicero parse "/Users/tmb/Coding/trustblocks/cicero-template-library/src/latedeliveryandpenalty"]) (-> (process ci {:out :string}) deref :out)

borkdude15:12:53

If you are in your default shell, what do you get for which cicero?

tbrooke15:12:48

/Users/tmb/.nvm/versions/node/v16.1.0/bin/cicero

borkdude15:12:53

this does work for me:

$ bb -e "@(babashka.process/process '[nbb -e (+ 1 2 3)] {:inherit true}) nil"
6

borkdude15:12:40

nbb is also a global installable node CLI

borkdude15:12:49

perhaps you can try your same code in bb from your shell. it might have to do something with the PATH setting inside your Java environment

tbrooke15:12:12

(-> (process ’[nbb -e (+ 1 2 3)]) {:inherit true}))

tbrooke15:12:43

Execution error (IOException) at java.lang.ProcessImpl/forkAndExec (ProcessImpl.java:-2). ; error=2, No such file or directory

tbrooke15:12:20

from the command line : ~ bb -e "@(babashka.process/process '[nbb -e (+ 1 2 3)] {:inherit true}) nil" 6

borkdude15:12:47

are you running this from IntelliJ or something like this?

borkdude15:12:12

Try starting VSCode from your terminal with code .

borkdude15:12:15

this should fix the issue I think

tbrooke15:12:23

It works — still not as fast as I hoped but better than the old way — iIt still returns all the output — Isn’t there a piping command - ie I get: “10:31:23 AM - INFO: Loading a default text/sample.md file. which is an informational message preceeding the output

borkdude15:12:13

that CLI should write that to stderr, not stdout

tbrooke15:12:12

I ran into that before when I was calling out to the CLI and just used Clojure to pull it out since the same heading appears on everything

tbrooke16:12:29

Sorry for all the confusion — One final Question even with process this is slow - like 4 seconds — It seems to me that the API for the CLI- which is not the same as the low level API in the docs but the CLI interface could be converted to something else- nbb doesn’t really help me since it needs to run from the command line — maybe there is a way to cache nbb in a process - or maybe I need to use shadow (It currently has trouble compiling - it compiles nicely under nbb and it will in shadow with some options. Here is what I found in the CLI Code that is a short sample of how the CLI works. If I could just call Cicero with some args I’d be home free: ‘use strict’; const Logger = require(‘@accordproject/concerto-core’).Logger; const Commands = require(‘./lib/commands’); require('yargs') .scriptName('cicero') .usage('$0 <cmd> [args]') .demandCommand(1, '# Please specify a command') .recommendCommands() .strict() .command('parse', 'parse a contract text', (yargs) => { yargs.option('template', { describe: 'path to the template', type: 'string' });

borkdude16:12:26

@U054219BT you could just write this code in a .js file but no matter what, you need to launch node with this js file

borkdude16:12:35

to you need to shell out in any case

borkdude16:12:58

unless you use a JavaScript engine in Java to load these libraries. GraalVM polyglot can do this

tbrooke16:12:50

That is the drawback to shadow since I would rather be in the jvm don't babashka/nbb use Graal under the hood couldn't they just run under Graal without the shell

borkdude16:12:32

if you run GraalVM's JVM you could start the JS engine once

borkdude16:12:37

and then keep using it

borkdude16:12:57

their JS engine also works in a regular JVM, but it's slower, maybe performance doesn't matter to you that much

borkdude16:12:03

it's called graaljs

borkdude16:12:35

Here is an example: https://github.com/applied-science/darkstar/blob/master/src/applied_science/darkstar.clj I'm not sure if your cicero app depends on any node.js specifics or if it's JS-platform agnostic

borkdude16:12:14

Another approach could be to wrap this cicero thing into a Node.js web app and host it as a separate service and make calls to that