Hey @borkdude I started getting some errors after upgrading 1.12.196 -> 1.12.201.
Released a new version with the fix: https://clojurians.slack.com/archives/C015AL9QYH1/p1750010529889959
$ bb -m com.fnguy.phuzql.cli.picker
----- Error --------------------------------------------------------------------
Type: clojure.lang.ExceptionInfo
Message: Could not resolve symbol: taoensso.truss/try*
Data: {:type :sci/error, :line 17, :column 1, :file "com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc", :phase "analysis"}
Location: com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
Phase: analysis
----- Context ------------------------------------------------------------------
31: (log/debug "Event loop started")
32: (let [running? (atom true)]
33: (async/go-loop []
34: (async/<! (async/timeout resolution-ms))
35: (enc/catching
^--- Could not resolve symbol: taoensso.truss/try*
36: (sp/receive-events! event-queue env
37: (fn [env {:keys [target] :as event}]
38: (log/trace "Received event" event)
39: (if-not target
40: (log/warn "Event did not have a session target. This queue only supports events to charts." event)
----- Stack trace --------------------------------------------------------------
com.fulcrologic.statecharts.event-queue.core-async-event-loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
com.fulcrologic.statecharts.event-queue.core-async-event-loop/loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
clojure.core/loop - <built-in>
clojure.core/fn - <built-in>
com.fulcrologic.statecharts.event-queue.core-async-event-loop/go - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:33:5
... (run with --debug to see elided elements)
com.fulcrologic.statecharts.event-queue.core-async-event-loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fnguy.phuzql.statecharts - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/statecharts.cljc:2:3
com.fnguy.phuzql.map-select-walker2 - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/map_select_walker2.clj:2:3
com.fnguy.phuzql.cli.picker - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/cli/picker.clj:2:3
user - <expr>:1:10
(py3-9_global) ✘-1 /tmp/dev_mounted_phuzql [main L|✚ 4…10]
+13:06 $ /tmp/bb --version
babashka v1.12.196
The older version still works though.I wonder if it's related to our last convo about Timbre https://clojurians.slack.com/archives/CLX41ASCS/p1749058086178649
can you do some more bisecting, e.g. try the 200 version and see if that still worked? also a more minimal code repro would be nice
Yeah, it's only the latest that breaks.
I upgraded timbre to 6.7.0 and perhaps it changed some macro to emit code to "truss" which I never saw before in bb related code.
hmm.
encore seems like a high churn library
taoensso/timbre uses encore (so I had to use encore macros in bb) but now encore uses truss
I could just downgrade by bb for now, not a big deal. Just thought I'd give you a heads up about the breaking change.
thank you very much, fixing it now
Wonder if I should just make the jump to Telemere. Besides the point, I suppose. Thanks for taking a look.
telemere doesn't work in bb btw
FWIW, part of why we moved away from timbre was the high level of churn and the interdependence between all of that maintainer's libraries.
What other logging options are there for babashka? Can it use any of the basic Java logging stuff?
@seancorfield bb has clojure.tools.logging as the logging "interface" and timbre as the logging impl. I chose timbre because you don't need any config files (which is a no go for one-file scripts) and it's easy to use from clojure
it has been part of bb for several years now (long before telemere)
the taoensso.encore/catching this is just exposed for timbre since one of their logging macros expands into it, but incidentally it also made other libraries like mentioned in the OP work (which is a nice bonus). but the macroexpansion changed to yet another sub library
Ah, interesting... I know slf4j can be a nuisance in terms of nop/multiple deps (which is c.t.l's default) and log4j requires some minimal configuration. What about j.u.l as the implementation? Does it have reasonable defaults?
I'm by no means a logging expert. In the commercial Clojure projects I've worked on, I've always encountered timbre, it wasn't even my own choice, so at the time it seemed like a good choice. Of course I could add j.u.l. but so far not a lot of people have asked for it. I won't remove timbre since that would be a major breaking change
I guess for a library like in the OP it would be better to just rely on clojure.tools.logging and not bring in other logging deps
I mean this one: https://github.com/fulcrologic/statecharts
Here's the fix: https://github.com/babashka/babashka/pull/1830
Do you mean it would be better if the SC lib didn't use Timbre? Users of the lib don't really have much say about that, other than forking ofc.
I mean, if I would write a library that needed logging, I'd try to rely solely on clojure.tools.logging and not bring in other deps (like encore or truss just because they provide some minor convenience around exception catching)
the library doesn't even directly depend on encore, yet it uses it, which is sloppy: https://github.com/fulcrologic/statecharts/blob/b7ebeb080724dbeead94f73bcdc1963eecc531ff/deps.edn#L3
Understandable. I guess authors could have any number of reasons for choosing the stack for their libs. Perhaps in this case it's just to be more consistent with the rest of the author's related libs.
@alex.sheluchin do you perhaps have the whole code of your cli? I'm trying to add some CI tests for statecharts but I don't know which namespaces it uses. Not familiar with the lib
One sec..
@borkdude I don't have the CLI pushed yet but perhaps this might be enough for your test? https://github.com/sheluchin/fnguy-examples/blob/main/examples/fulcro_statecharts/src/com/fnguy/coin_flip.cljc
The test suite of statecharts unfortunately isn't able to run in bb since it loads ClojureScript, etc.
I'll try to add your program as a sort of test
hmm:
[com.fnguy.statecharts :as fnsc]is there some simple example I could add as a test?
That ns is just a few helper functions to simplify interacting with the statecharts.
Do you need it exposed as a top-level var or something?
I just want one smoke gun test for statecharts to see if it runs in bb
as a single script
claude wrote this, can you check if it makes any sense?
#!/usr/bin/env bb
(require '[babashka.deps :as deps])
;; Add the dependency
(deps/add-deps '{:deps {com.fulcrologic/statecharts {:mvn/version "1.3.0"}}})
;; Require the statecharts namespace
(require '[com.fulcrologic.statecharts :as sc])
(defn smoke-test []
"One simple test to verify fulcro-statecharts works"
(println "🔥 Testing fulcro-statecharts in Babashka...")
(try
;; Create a simple toggle statechart
(let [chart-def {:id :toggle
:initial :off
:states {:off {:on {:TOGGLE {:target :on}}}
:on {:on {:TOGGLE {:target :off}}}}}
chart (sc/statechart chart-def)
initial-state (sc/start chart)]
(println "✓ Created statechart")
(println (str "✓ Initial state: " (sc/current-state initial-state)))
;; Test transition
(let [toggled-state (sc/trigger chart initial-state :TOGGLE)]
(println (str "✓ After TOGGLE: " (sc/current-state toggled-state)))
(if (= :on (sc/current-state toggled-state))
(println "🎉 SUCCESS! Fulcro Statecharts works in Babashka!")
(println "❌ FAIL: Unexpected state"))))
(catch Exception e
(println (str "❌ ERROR: " (.getMessage e))))))
;; Run the test
(smoke-test)sc/statechart
doesn't even seem to exist. But this is the kind of code I need. Just a simple example. I can't even see such an example in the README of statecharts and when looking at the test suite, I don't know even where to beginNo, that code's a bit weird. But if I add a bb.edn to my repo we can trigger that failure easily with bb -m com.fnguy.statecharts alone.
There's probably a much more minimal smoke test though. lms
for starters, I could just require the main namespace and do nothing else.
I'm guessing that would be sufficient.
usually that's only a good start, but a test would reveal runtime errors
I'll just make this as a start, if you want to make another PR with some example, up to you
I'll add a flip-once you can call.
One a working version:
+14:23 $ /tmp/bb -m com.fnguy.coin-flip/flip-once
2025-06-14T18:24:06.556Z xps DEBUG [com.fulcrologic.statecharts.event-queue.core-async-event-loop:31] - Event loop started
2025-06-14T18:24:06.560Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:757] - Processing event on statechart => :com.fnguy.coin-flip/coin-flips
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:199] - target(s) => [:state/coin]
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:184] - target => :state/coin
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:186] - target-element => :state/coin
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:205] - (get-effective-target-states env t) => #{:state/coin}
2025-06-14T18:24:06.563Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:206] - (chart/nearest-ancestor-state statechart t) => :initial23309
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:213] - (:id (chart/find-least-common-compound-ancestor statechart (into (if tsource [tsource] []) tst
ates))) => :ROOT
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:199] - target(s) => [:state/coin]
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:184] - target => :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:186] - target-element => :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:368] - entry set => [#{:state/coin :state/heads} #{:state/coin} {}]
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:372] - Enter :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:340] - Execute content of {:id :transition23310, :target [:state/heads], :type :external, :node-type
:transition, :parent :initial23311}
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:386] - (chart/final-state? statechart s) => false
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:372] - Enter :state/heads
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:386] - (chart/final-state? statechart s) => false
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:404] - after enter states: => #{:state/coin :state/heads}
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:434] - conflicting? => #{}
showing state {:wmem #:com.fulcrologic.statecharts{:history-value {}, :statechart-src :com.fnguy.coin-flip/coin-flips, :configuration #{:state/coin :state/heads}, :running? true, :macrostep-d
one? false, :initialized-states #{}, :session-id 1}}@borkdude https://github.com/sheluchin/fnguy-examples/commit/9ceded7a58cd6118192e275dda8cf238c7eb222e how's that?
/tmp/bb -m com.fnguy.coin-flip/flip-once gives the above but latest bb gives the error:
+14:24 $ bb -m com.fnguy.coin-flip/flip-once
----- Error --------------------------------------------------------------------
Type: clojure.lang.ExceptionInfo
Message: Could not resolve symbol: taoensso.truss/try*
Data: {:type :sci/error, :line 17, :column 1, :file "com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc", :phase "analysis"}
Location: com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
Phase: analysis
----- Context ------------------------------------------------------------------
31: (log/debug "Event loop started")
32: (let [running? (atom true)]
33: (async/go-loop []
34: (async/<! (async/timeout resolution-ms))
35: (enc/catching
^--- Could not resolve symbol: taoensso.truss/try*
36: (sp/receive-events! event-queue env
37: (fn [env {:keys [target] :as event}]
38: (log/trace "Received event" event)
39: (if-not target
40: (log/warn "Event did not have a session target. This queue only supports events to charts." event)
----- Stack trace --------------------------------------------------------------
com.fulcrologic.statecharts.event-queue.core-async-event-loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
com.fulcrologic.statecharts.event-queue.core-async-event-loop/loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
clojure.core/loop - <built-in>
clojure.core/fn - <built-in>
com.fulcrologic.statecharts.event-queue.core-async-event-loop/go - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:33:5
... (run with --debug to see elided elements)
com.fulcrologic.statecharts.event-queue.core-async-event-loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fulcrologic.statecharts.event-queue.core-async-event-loop - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fnguy.statecharts - /home/alex/repos/personal-projects/fnguy-examples/examples/fulcro_statecharts/src/com/fnguy/statecharts.cljc:2:3
com.fnguy.coin-flip - /home/alex/repos/personal-projects/fnguy-examples/examples/fulcro_statecharts/src/com/fnguy/coin_flip.cljc:2:3
user - <expr>:1:10is it possible to make it self-contained, i.e. not dependent on another namespace in your project and avoid the logging, so it can be tested against a value or so?
no sweat if you don't but it would make testing easier and more robust.
I'll get back to you with a snippet a bit later
I added the require tests to this PR: https://github.com/babashka/babashka/pull/1830
specifically to this file: https://github.com/babashka/babashka/pull/1830/files#diff-adae44708d2152731096e3ddb89a2273b35f80459b1233a42ea9d8cf1423c751
I merged the PR. Feel free to follow up with something later. Once master CI finishes you can test with:
bash <(curl ) --dev-build --dir /tmp I'll probably make a release for this, since it's annoying it broke again
Sounds good. Thanks again. I'll add a PR for a minimal statecharts test today or tomorrow. Just got back from a short vacation and have a few things to juggle.
sure, no hurry and thanks in advance!
Do you just throw whatever code you want to try running into that statechart_test.clj file? No asserts and stuff?
no, all the code are deftest + is based tests or I just straightup run the library code of existing libs
only in special cases do I copy tests + adapt them a bit but with statecharts, I just don't know where to begin
I'd do a smoketest myself if I saw an example in the README but it's pretty terse
Would this do?
(ns babashka.statecharts-test
(:require
[com.fulcrologic.statecharts :as sc]
[com.fulcrologic.statecharts.chart :refer [statechart]]
[com.fulcrologic.statecharts.elements :refer [state transition]]
[com.fulcrologic.statecharts.events :refer [new-event]]
[com.fulcrologic.statecharts.protocols :as sp]
[com.fulcrologic.statecharts.simple :as simple]))
(def light-switch
(statechart {:initial :off}
(state {:id :on}
(transition {:event :toggle, :target :off}))
(state {:id :off}
(transition {:event :toggle, :target :on}))))
(let [;; 1. Set up the environment and processor
env (simple/simple-env)
_ (simple/register! env ::switch light-switch)
processor (::sc/processor env)
;; 2. Start the machine and get initial state (s0)
_ (println "--- Starting Light Switch Machine ---")
s0 (sp/start! processor env ::switch {::sc/session-id 1})
_ (println "Initial state:" (::sc/configuration s0))
;; 3. Send the first event, get next state (s1)
_ (println "\nSending event: :toggle")
s1 (sp/process-event! processor env s0 (new-event :toggle))
_ (println "Current state:" (::sc/configuration s1))
;; 4. Send the second event, get final state (s2)
_ (println "\nSending event: :toggle")
s2 (sp/process-event! processor env s1 (new-event :toggle))]
;; 5. Print the final state from the last step
(println "Current state:" (::sc/configuration s2)))
Pretty simple, just had Gemini whip it up with few small adjustments.
fails with v1.12.201
Oh, I think I misread your last message. So you would prefer a few assertions against the lib fn calls?
ok let me try it
works:
Ran 1 tests containing 3 assertions.
0 failures, 0 errors.
{:test 1, :pass 3, :fail 0, :error 0}Cool. That should cover the basics to make sure the lib can run in bb, I think.
thanks, I'll add it