How to define target env in compile time while building .cljs? - node.js

I want to compile my .cljs file for both browser and node.js environments, to get server side rendering. As I understand, there's no way to define cljs env in compile time with reader macro conditions like:
#?(:clj ...)
#?(:cljs ...)
so, I can't easily tell compiler to process something like #?(:cljs-node ...) in node.js env.
Second option I see here is to develop a macro file which will define env at compile time. But how to define that current build is targeting node.js? May be, I could pass some params somehow to compiler or get :target compiler param?
Here are my boot files:
application.cljs.edn:
{:require [filemporium.client.core]
:init-fns [filemporium.client.core/init]}
application.node.cljs.edn:
{:require [filemporium.ssr.core]
:init-fns [filemporium.ssr.core/-main]
:compiler-options
{:preamble ["include.js"]
:target :nodejs
:optimizations :simple}}

I am not aware of a public API to achive this. However, you might use cljs.env/*compiler* dynamic var in your macro to check the target platform (i.e. NodeJS vs browser) configured with :target in your :compiler-options and either emit or suppress the code wrapped in the macro:
(defn- nodejs-target?
[]
(= :nodejs (get-in #cljs.env/*compiler* [:options :target])))
(defmacro code-for-nodejs
[& body]
(when (nodejs-target?)
`(do ~#body)))
(defmacro code-for-browser
[& body]
(when-not (nodejs-target?)
`(do ~#body)))
(code-for-nodejs
(def my-variable "Compiled for nodejs")
(println "Hello from nodejs"))
(code-for-browser
(def my-variable "Compiled for browser")
(println "Hello from browser"))

Here is up to date code working on org.clojure/clojurescript {:mvn/version "1.11.60"}
(ns contrib.cljs-target
#?(:cljs (:require-macros [contrib.cljs-target]))
#?(:cljs (:require [goog.object :as object])))
; preferred runtime check for target through public API https://cljs.github.io/api/cljs.core/STARtargetSTAR
#?(:cljs (defn nodejs? [] (= cljs.core/*target* "nodejs")))
#?(:cljs (defn browser? [] (= cljs.core/*target* "default")))
; undocumented hack, only works in macros. https://stackoverflow.com/a/47499855
#?(:clj (defn- cljs-target [] (get-in #cljs.env/*compiler* [:options :closure-defines 'cljs.core/*target*])))
(defmacro do-nodejs [& body] (if (= "nodejs" (cljs-target)) `(do ~#body)))
(defmacro do-browser [& body] (if-not (= "nodejs" (cljs-target)) `(do ~#body)))

Related

datalevin, concurrency, transactions

I am using latest Datalevin version 0.7.8 and wrote the following small program:
(ns datalevintest.core
(:require [datalevin.core :as dc]))
(def store (System/getenv "DBSTORE"))
(def conn (datalevin.core/get-conn store {} {:auto-entity-time? true :validate-data? true}))
(defn -main [& _]
(dotimes [i 5]
(future
(locking ::println (println "Starting thread"))
(try
(dotimes [j 100]
(dc/transact! conn [{:i+j (+ i j)}])
(dc/with-transaction [tx-conn conn]
(dc/transact! tx-conn [{:i*j (* i j)}]))
(dc/q '[:find (pull ?e [*]) :in $ ?id :where [?e :db/id ?id]]
(dc/db conn) 2345))
(catch Throwable t (.printStackTrace t))
(finally (println "Thread" i "done")))))
(println "END"))
Nondeterministically, sometimes I get the following:
clojure.lang.ExceptionInfo: Fail to transact to LMDB: "Transaction is not in ready state" {}
at datalevin.binding.java.LMDB.transact_kv(java.clj:484)
at datalevin.storage.Store.load_datoms(storage.cljc:376)
at datalevin.db$local_transact_tx_data.invokeStatic(db.cljc:1236)
at datalevin.db$local_transact_tx_data.invoke(db.cljc:963)
at datalevin.db$transact_tx_data.invokeStatic(db.cljc:1274)
at datalevin.db$transact_tx_data.invoke(db.cljc:1250)
at datalevin.core$with.invokeStatic(core.cljc:291)
at datalevin.core$with.invoke(core.cljc:285)
at datalevin.core$with.invokeStatic(core.cljc:288)
at datalevin.core$with.invoke(core.cljc:285)
at datalevin.core$_transact_BANG_$fn__13128$fn__13129.invoke(core.cljc:550)
at clojure.lang.Atom.swap(Atom.java:37)
at clojure.core$swap_BANG_.invokeStatic(core.clj:2356)
at clojure.core$swap_BANG_.invoke(core.clj:2349)
at datalevin.core$_transact_BANG_$fn__13128.invoke(core.cljc:549)
at datalevin.core$_transact_BANG_.invokeStatic(core.cljc:548)
at datalevin.core$_transact_BANG_.invoke(core.cljc:545)
at datalevin.core$transact_BANG_.invokeStatic(core.cljc:643)
at datalevin.core$transact_BANG_.invoke(core.cljc:555)
at datalevin.core$transact_BANG_.invokeStatic(core.cljc:640)
at datalevin.core$transact_BANG_.invoke(core.cljc:555)
at datalevintest.core$save_BANG_.invokeStatic(core.clj:10)
at datalevintest.core$save_BANG_.doInvoke(core.clj:9)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at datalevintest.core$_main$fn__13261$fn__13265.invoke(core.clj:32)
at datalevintest.core$_main$fn__13261.invoke(core.clj:27)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
(You may need to run the program multiple times to get the error.)
Less often I get the following:
clojure.lang.ExceptionInfo: Fail to get-first: nil {:dbi "datalevin/eav", :k-range [:all-back], :k-type :eav, :v-type :id}
at datalevin.scan$get_first.invokeStatic(scan.cljc:233)
at datalevin.scan$get_first.invoke(scan.cljc:229)
at datalevin.binding.java.LMDB.get_first(java.clj:502)
at datalevin.binding.java.LMDB.get_first(java.clj:500)
at datalevin.storage.Store.init_max_eid(storage.cljc:300)
at datalevin.db$new_db.invokeStatic(db.cljc:387)
at datalevin.db$new_db.invoke(db.cljc:379)
at datalevintest.core$_main$fn__13261$fn__13265$fn__13276.invoke(core.clj:30)
at datalevintest.core$_main$fn__13261$fn__13265.invoke(core.clj:30)
at datalevintest.core$_main$fn__13261.invoke(core.clj:27)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
If I move the creation of connection into the future wiht create-conn, I get another exception:
java.lang.NullPointerException: Cannot read field "e"
at datalevin.storage.Store.init_max_eid(storage.cljc:302)
at datalevin.db$new_db.invokeStatic(db.cljc:387)
at datalevin.db$new_db.invoke(db.cljc:379)
at datalevin.db$empty_db.invokeStatic(db.cljc:399)
at datalevin.db$empty_db.invoke(db.cljc:392)
at datalevin.core$create_conn.invokeStatic(core.cljc:529)
at datalevin.core$create_conn.invoke(core.cljc:488)
at datalevintest.core$_main$fn__13252.invoke(core.clj:14)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
(This one also breaks the database file so the application will not start up the next time.)
The issue comes up in a multithreaded environment and sounds like a concurrency problem. My first idea was that the same connection should'nt be used across different threads, however, the code of get-conn says the same connection will be reused when it alrady exists for a directory. The documentation does not mention multithreading.
What is the error in my code causing the problem and how can I make it safer?
This bug was fixed by version 0.7.9 released half an hour after the question was posted.

intero error: wrong-type-argument stringp nil

I'm trying to get intero running. After install, opening a Haskell file from an existing stack project results in:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
signal(wrong-type-argument (stringp nil))
flycheck-buffer()
flycheck-buffer-automatically()
flycheck-perform-deferred-syntax-check()
set-window-buffer(#<window 1 on Lib.hs> #<buffer Lib.hs>)
window--display-buffer(#<buffer Lib.hs> #<window 1 on Lib.hs> reuse ((inhibit-same-window)))
display-buffer-same-window(#<buffer Lib.hs> ((inhibit-same-window)))
display-buffer(#<buffer Lib.hs> (display-buffer-same-window (inhibit-same-window)))
pop-to-buffer(#<buffer Lib.hs> (display-buffer-same-window (inhibit-same-window)) nil)
pop-to-buffer-same-window(#<buffer Lib.hs>)
find-file("~/test/src/Lib.hs" t)
funcall-interactively(find-file "~/test/src/Lib.hs" t)
call-interactively(find-file nil nil)
command-execute(find-file)
When I run flycheck-buffer in the same buffer, nothing happens, even when there are errors in the source code.
Here are the contents of my .emacs file:
(setq debug-on-error t)
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(package-initialize)
(package-refresh-contents)
(package-install 'intero)
(add-hook 'haskell-mode-hook 'intero-mode)
Since I'm on Mac Os I also tried adding (as suggested on the flycheck page):
(package-install 'exec-path-from-shell)
(exec-path-from-shell-initialize)
But it makes no difference.
Here are the installed package versions:
$ ls ~/.emacs.d/elpa/
archives/
company-20191114.1356/
dash-20191109.1327/
epl-20180205.2049/
flycheck-20191126.1329/
haskell-mode-20191120.1923/
intero-20191103.1239/
pkg-info-20150517.1143/
This is using GNU Emacs 26.3.
TL;DR
I found two issues and a (at least temporary) fix for each of them.
I am submitting pull requests for both of them, but in the mean time you can fix the issue for yourself either by editing the intero.el file directly, or (recommended way) by using the great el-patch package.
1) intero-ghc-version not set
This is due to the fact of using the intero-ghc-version local variable instead of calling the function (intero-ghc-version) in the intero-ghci-output-flags function (L.2668) intero.el
Fix: patch the function intero-ghci-output-flags :
replace
(split-string intero-ghc-version "\\."))))
by
(split-string (intero-ghc-version) "\\."))))
(notice the added parentheses)
2) misuse of append for string concatenation in intero-start-process-in-buffer
append is for lists, concat is for strings, an easy mistake, especially when in Haskell String is equivalent to [Char] (so technically... a list!)
fix: patch the function intero-start-process-in-buffer, L.2335 of the intero.el:
replace
(process-send-string process (append ":set " flag "\n")))
by
(process-send-string process (concat ":set " flag "\n")))
line 2335 of the current version of the source code, using el-patch)
Once these modifications are made, you should be up and running!
Initial answer
Same issue here.
Not a definitive answer, but I have the same issue and might have pinned down the issue to the function intero-ghci-output-flags being run as the intero-ghc-version variable is not set properly.
Feel free to correct me as I might have missed some things.
By following the error messages, I confirm it happens in (flycheck-start-current-syntax-check checker) in the flycheck-buffer function.
Running this directly from the haskell buffer shows that the error happens when calling (split-string intero-ghc-version "\\.") from the intero-ghci-output-flags function in the intero.el file (Line 2671).
This tries to split the intero version (as set by the intero-ghc-version function above in the file).
It seems the variable's value is nil, as confirmed by running M-x describe-variable -> intero-ghc-version.
During my tests I got seemingly imprevisible results from (intero-ghc-version).
Sometimes (at least on the first run?) it returns "8.4.4",
sometimes it fails with "Wrong type argument: stringp, (58 115 101 116 32 45 102 111 98 106 ...)
I am able to manually run the function intero-ghci-output-flags and get the proper output without error, once, and it fails if I run it a second time.
the function (intero-ghc-version-raw) consistently returns "8.4.4" however.
After experimenting the error message that spontaneously appears is transformed to:
Debugger entered--Lisp error: (wrong-type-argument stringp (58 115 101 116 32 45 102 111 98 106 101 99 116 45 99 111 100 101 . "\n"))
process-send-string(#<process stack> (58 115 101 116 32 45 102 111 98 106 101 99 116 45 99 111 100 101 . "\n"))
#f(compiled-function (flag) #<bytecode 0x1785fe9>)("-fobject-code")
mapc(#f(compiled-function (flag) #<bytecode 0x1785fe9>) ("-fobject-code"))
intero-start-process-in-buffer(#<buffer intero:backend:pubiber /home/mika/programmation/haskell/pubiber> nil #<buffer Lib.hs> nil)
intero-get-worker-create(backend nil #<buffer Lib.hs> nil)
intero-buffer(backend)
intero-eldoc()
The ASCII char sequence in the error message is ":set -fobject-code".
The "-fobject-code" in the message is the result of the intero-ghci-output-flags function, so it seems it finally worked properly but the rest of the code failed.
Note:
The fact that the file gets re-evaluated whenever intero tries to start a session might to explain why I get inconsistent results when running the functions several times.
PS running arch linux, system updated a few minutes ago, all emacs package updated.
---- EDIT ----
So after looking a bit more, in the function intero-start-process-in-buffer, that uses the flags to start the intero process in the lines 2334-2337:
(set-process-query-on-exit-flag process nil)
(mapc
(lambda (flag)
(process-send-string process (append ":set " flag "\n")))
(intero-ghci-output-flags))
(process-send-string process ":set -fdefer-type-errors\n")
they use append instead of concat to create the command.
replacing append by concat fixes this second error, and intero boots normally and seems to work properly (after setting intero-ghc-version).
---- EDIT 2 ----
Just figured out the original issue:
The function uses the variable intero-ghc-version instead of calling the function with the same name. The function is supposed to act as a lazy loader of the value, calling intero-ghc-version-raw the first time, and returning the cached value the subsequent times.
Calling the variable directly didn't allow the value to be set initially.
See the TL;DR for the temporary fix.

java.lang.IllegalArgumentException error depending on symbol names used - Clojure

I am a beginner at Clojure. I am performing one operation twice, but with changed symbols lang against language
One case it is working well, another is throwing an error:
java.lang.IllegalArgumentException: No method in multimethod 'my-method' for dispatch value: null
I am not sure if it is caused by an Clojure syntax or there is something wrong in my linux configuration. I have Debian Stretch and boot.clj.
The error happens in the terminal. Here you are the both peaces of code an the error:
s#lokal:~$ boot repl
nREPL server started on port 36091 on host 127.0.0.1 - nrepl://127.0.0.1:36091
java.lang.Exception: No namespace: reply.eval-modes.nrepl found
REPL-y 0.4.1, nREPL 0.4.4
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_181-8u181-b13-2~deb9u1-b13
Exit: Control+D or (exit) or (quit)
Commands: (user/help)
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Find by Name: (find-name "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
(user/clojuredocs name-here)
(user/clojuredocs "ns-here" "name-here")
boot.user=> (do
#_=> (defmulti my-method (fn[x] (x "lang")))
#_=> (defmethod my-method "English" [params] "Hello!")
#_=> (def english-map {"id" "1", "lang" "English"})
#_=> (my-method english-map)
#_=> )
"Hello!"
boot.user=>
boot.user=> (do
#_=> (defmulti my-method (fn[x] (x "language")))
#_=> (defmethod my-method "English" [params] "Hello!")
#_=> (def english-map {"id" "1", "language" "English"})
#_=> (my-method english-map)
#_=> )
java.lang.IllegalArgumentException: No method in multimethod 'my-method' for dispatch value: null
boot.user=>
I must add that before it worked with language but not with lang. It also turned to work or did not when I was changing a my-method symbol name with mymetho-d or greeting.
defmulti defines a var, and subsequent calls to defmulti with the same name do nothing, so your second defmulti call is ineffective and the original dispatch function remains. There's remove-method and remove-all-methods for removing defmethod definitions, but to remove a defmulti definition (without restarting REPL) you can use alter-var-root to set the var to nil:
(defmulti my-method (fn [x] (x "lang")))
(defmethod my-method "English" [params] "Hello!")
(def english-map {"id" "1", "lang" "English"})
(my-method english-map)
=> "Hello!"
(alter-var-root #'my-method (constantly nil)) ;; set my-method var to nil
(def english-map {"id" "1", "language" "English"})
(defmulti my-method (fn [x] (x "language")))
(defmethod my-method "English" [params] "Hello!")
(my-method english-map)
=> "Hello!"
You can use ns-unmap to similar effect:
(ns-unmap *ns* 'my-method)

How to setup classpath for slimv and ritz

I would like to resolve my problem for classpath.Could you tell me how to do?
I can do the following.
I can eval (+ 1 1) in vim(slimv) by pushing ,e.
Then slimv display the followings.
user>
(+ 1 1)
2
However,I can not do the followings.
1.When I eval the the following code in vim(slimv) by pushing ,e,
(use '[clojure.contrib.str-utils :only (re-split)])
2.Slimv displays the following error.
; Evaluation aborted on java.io.FileNotFoundException: Could not locate clojure/contrib/str_utils__init.class or clojure/contrib/str_utils.clj on classpath:
My enviroment is the followings.
macvim 7.3.754
lein 2.0.0
slimv 0.9.9
ritz 0.7.0
project.clj
(defproject helloworld "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]]
:plugins [[lein-ritz "0.7.0"]]
)
~/.lein/profiles.clj
{:user {:plugins [
[lein-ritz "0.7.0"]
]}}
ref
lein ritz setup error
Have you tried clojure.string?
(use '[clojure.string :only (split)])
(split "clojure8*)-6contrib&(*does^&$not*_^%exist^*#anymore" #"[^a-zA-Z]+")
=> ["clojure" "contrib" "does" "not" "exist" "anymore"]
BTW all clojure.contrib have been migrated to separated libraries http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

How do I write to a zip file in Common Lisp?

I'm able to open a zip entry and tweak the contents, but I can't figure out how to save them.
The API for CL ZIP is wanting.
Specs:
ZIP
Quicklisp
MacPorts CLISP 2.49
Aquamacs 2.1 (Emacs 23.2)
Mac OS X 10.6.4
MacBook Pro 5,1
; Removes newlines at the beginning of PRE tags in Sigil-edited ePub files.
;
; See http://code.google.com/p/sigil/issues/detail?id=655
;
; Andrew Pennebaker
; 16 Nov 2010
; Requires Quicklisp.
; http://www.quicklisp.org/
(ql:quickload "zip")
(ql:quickload "cl-ppcre")
(defvar *epub* nil)
(defvar *epub-contents* nil)
(defvar *epub-out* nil)
(defun load-epub (filename)
(setq *epub* (zip:open-zipfile filename)))
(defun close-epub ()
(zip:close-zipfile *epub*)
(setq *epub* nil)
(setq *epub-contents* nil))
(defun gather-epub-contents ()
(zip:do-zipfile-entries (name entry *epub*)
(push name *epub-contents*)))
(defun is-html-file (name)
(if (cl-ppcre:scan ".+\\.htm[l]?$" name) t nil))
(defun entry-name-to-html (name)
(flexi-streams:octets-to-string
(zip:zipfile-entry-contents
(zip:get-zipfile-entry name *epub*))))
(defun clean (html)
(values
(cl-ppcre:regex-replace-all
"<pre[^>]*>(\\s)*"
(cl-ppcre:regex-replace-all "\\s+</pre>" html "</pre>")
"<pre>")))
As per the documentation of the Common Lisp ZIP library, you have to obtain a separate handle to write to the zip file. Probably you can extract the contents to a folder, tweak the contents and compress the whole folder with a single call to (zip path-name source-folder).
Using a temp file, you're able to unzip, modify, and rezip.
See sigil-clean.cl

Resources