syl20bnr/spacemacs

[Clojure] nREPL server doesn't start if sayid was not compiled during the current session

Closed this issue · 18 comments

Description :octocat:

Spacemacs cannot download sayid artifacts from Maven Central. They have moved to Clojars.
See https://clojars.org/com.billpiel/sayid

Reproduction guide 🪲

  1. Start Emacs
  2. install Clojure layer
  3. add support for sayid
  4. open a Clojure project
  5. try to start a REPL
(clojure :variables
               clojure-enable-sayid t)

Observed behaviour: 👀 💔
The REPL is no started. The message buffer shows the following error message:

[nREPL] Starting server via /home/allentiak/opt/bin/clojure -A:test -Sdeps '{:deps {nrepl {:mvn/version "0.8.0"} com.billpiel/sayid {:mvn/version "nil"} refactor-nrepl {:mvn/version "2.5.0"} cider/cider-nrepl {:mvn/version "0.25.3"}}}' -m nrepl.cmdline --middleware '["com.billpiel.sayid.nrepl-middleware/wrap-sayid", "refactor-nrepl.middleware/wrap-refactor", "cider.nrepl/cider-middleware"]'
error in process sentinel: nrepl-server-sentinel: Could not start nREPL server: Error building classpath. Could not find artifact com.billpiel:sayid:jar:nil in central (https://repo1.maven.org/maven2/)

error in process sentinel: Could not start nREPL server: Error building classpath. Could not find artifact com.billpiel:sayid:jar:nil in central (https://repo1.maven.org/maven2/)

Expected behaviour: ❤️ 😄
The REPL is started normally.

System Info 💻

  • OS: gnu/linux
  • Emacs: 26.3
  • Spacemacs: 0.300.0
  • Spacemacs branch: ready-to-work (rev. 2ce32b4)
  • Graphic display: t
  • Distribution: spacemacs
  • Editing style: vim
  • Completion: helm
  • Layers:
(spacemacs-visual auto-completion emacs-lisp
                  (git :variables magit-diff-refine-hunk 'all magit-diff-adjust-tab-width t magit-diff-paint-whitespace t magit-diff-highlight-trailing t)
                  github helm
                  (markdown :variables markdown-live-preview-engine 'vmd)
                  multiple-cursors org
                  (shell :variables shell-default-height 30)
                  spell-checking syntax-checking
                  (version-control :variables version-control-diff-tool 'git-gutter+ version-control-global-margin t)
                  treemacs
                  (clojure :variables cljr-warn-on-eval nil clojure-enable-sayid t clojure-enable-clj-refactor t clojure-enable-linters t cider-repl-pop-to-buffer-on-connect 'display-only cider-clojure-cli-global-options "-A:test")
                  (parinfer :variables ensure t progn
                            (setq parinfer-extensions
                                  '(defaults pretty-parens evil smart-tab smart-yank)))
                  (keyboard-layout :variables kl-layout 'colemak-neio-inverted)
                  latex ess
                  (java :variables java-backend 'lsp)
                  html yaml)
  • System configuration features: XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GSETTINGS GLIB NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM THREADS LIBSYSTEMD LCMS2

Backtrace 🐾

<<BACKTRACE IF RELEVANT>>

I did some research, and it seems that Emacs get the expected sayid version from Maven Central.
However, as the package is not there, it only gets 'nil'...

Maybe a solution would be adding Clojars as a package repository? I think this should not be so difficult, but I have no idea how to do it...

Workaround: disable sayid in .spacemacs config file.

Now it works. It seems it was my mistake :-)

It happens again. It didn't...

BTW: Here's my .spacemacs.

Here's what happens:

  • If I start Spacemacs with sayid disabled, but enable it and reload the file, Spacemacs installs the package and configures it correctly to work with the REPL.
  • However, if I start Spacemacs with the package already enabled, the REPL fails to start (see error message above). In this case, disabling sayid and reloading the config file is not enough o make the REPL work again: I have to fully restart Spacemacs for this change to take effect.

Any clues regarding what could be causing this strange behavior?

Thats strange @allentiak I have just restarted emacs first without sayid support, afterwards with sayid support activated, I have opened a clojure file and started cider-jack-in-clj and I am getting

[nREPL] Starting server via /home/smile13241324/.local/bin/lein update-in :dependencies conj \[nrepl\ \"0.8.1\"\] -- update-in :plugins conj \[com.billpiel/sayid\ \"0.1.0\"\] -- update-in :plugins conj \[refactor-nrepl\ \"2.5.0\"\] -- update-in :plugins conj \[cider/cider-nrepl\ \"0.25.3\"\] -- repl :headless :host localhost
[nREPL] server started on 39217
[nREPL] Establishing direct connection to localhost:39217 ...
[nREPL] Direct connection to localhost:39217 established
evil-delete-line: Buffer is read-only: #<buffer *Messages*>
evil-line-move: End of buffer

However its interesting that in my case leiningen is used to run the repl and in your case clojure itself 😕
Here is my config

     (clojure :variables
              clojure-enable-fancify-symbols t
              clojure-enable-sayid t
              clojure-enable-clj-refactor t
              clojure-enable-linters '(clj-kondo joker))

Found out why closure itself is running your command, when you edit a single file this seems to happen, now I am seeing:

[nREPL] Starting server via /usr/bin/clojure -Sdeps '{:deps {nrepl {:mvn/version "0.8.1"} com.billpiel/sayid {:mvn/version "0.1.0"} refactor-nrepl {:mvn/version "2.5.0"} cider/cider-nrepl {:mvn/version "0.25.3"}}}' -m nrepl.cmdline --middleware '["com.billpiel.sayid.nrepl-middleware/wrap-sayid", "cider.nrepl/cider-middleware"]'
[nREPL] server started on 42779
[nREPL] Establishing direct connection to localhost:42779 ...
[nREPL] Direct connection to localhost:42779 established

Whats important is that in my call a fixed version of sayid is used, where as in your version nil is used as version string, maybe thats the issue?

However its interesting that in my case leiningen is used to run the repl and in your case clojure itself confused

@smile13241324 I use Clojure's CL, as I prefer deps.edn over Leiningen (or Boot).

in my call a fixed version of sayid is used, where as in your version nil is used as version string, maybe thats the issue?

Yes, @smile13241324. Somehow, Spacemacs got the version number right when I first installed the package, but it seems it "lost track" of it after I quit the program...

@allentiak so I have finally managed to reproduce the issue, my Spacemacs did not remove old packages therefore the old stored version of sayid was never deleted and was just working. Now I see the same behaviour, when I freshly install sayid it works as expected, when I restart emacs afterwards the version is gone and the call fails with:

error in process sentinel: Could not start nREPL server: OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
java.lang.IllegalArgumentException: Provided artifact is missing a version: [com.billpiel/sayid nil]
 at cemerick.pomegranate.aether$add_version_from_managed_coord.invokeStatic (aether.clj:654)
    cemerick.pomegranate.aether$add_version_from_managed_coord.invoke (aether.clj:646)
    cemerick.pomegranate.aether$add_version_from_managed_coords_if_missing.invokeStatic (aether.clj:682)
    cemerick.pomegranate.aether$add_version_from_managed_coords_if_missing.invoke (aether.clj:676)
    clojure.core$partial$fn__5824.invoke (core.clj:2624)
    clojure.core$map$fn__5851.invoke (core.clj:2753)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:51)
    clojure.lang.RT.seq (RT.java:531)
    clojure.lang.LazilyPersistentVector.create (LazilyPersistentVector.java:44)
    clojure.core$vec.invokeStatic (core.clj:377)
    clojure.core$vec.invoke (core.clj:367)
    cemerick.pomegranate.aether$merge_versions_from_managed_coords.invokeStatic (aether.clj:691)
    cemerick.pomegranate.aether$merge_versions_from_managed_coords.invoke (aether.clj:685)
    cemerick.pomegranate.aether$resolve_dependencies_STAR_.invokeStatic (aether.clj:793)
    cemerick.pomegranate.aether$resolve_dependencies_STAR_.doInvoke (aether.clj:707)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.core$apply.invoke (core.clj:660)
    cemerick.pomegranate.aether$resolve_dependencies.invokeStatic (aether.clj:815)
    cemerick.pomegranate.aether$resolve_dependencies.doInvoke (aether.clj:809)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.core$apply.invoke (core.clj:660)
    cemerick.pomegranate$add_dependencies.invokeStatic (pomegranate.clj:83)
    cemerick.pomegranate$add_dependencies.doInvoke (pomegranate.clj:57)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.classpath$get_dependencies_STAR_.invokeStatic (classpath.clj:289)
    leiningen.core.classpath$get_dependencies_STAR_.invoke (classpath.clj:282)
    clojure.lang.AFn.applyToHelper (AFn.java:165)
    clojure.lang.AFn.applyTo (AFn.java:144)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.core$memoize$fn__6862.doInvoke (core.clj:6353)
    clojure.lang.RestFn.invoke (RestFn.java:457)
    leiningen.core.classpath$get_dependencies$fn__6864.invoke (classpath.clj:338)
    leiningen.core.classpath$get_dependencies.invokeStatic (classpath.clj:336)
    leiningen.core.classpath$get_dependencies.doInvoke (classpath.clj:330)
    clojure.lang.RestFn.applyTo (RestFn.java:146)
    clojure.core$apply.invokeStatic (core.clj:671)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.classpath$resolve_managed_dependencies.invokeStatic (classpath.clj:449)
    leiningen.core.classpath$resolve_managed_dependencies.doInvoke (classpath.clj:436)
    clojure.lang.RestFn.invoke (RestFn.java:494)
    leiningen.core.project$load_plugins.invokeStatic (project.clj:763)
    leiningen.core.project$load_plugins.invoke (project.clj:758)
    leiningen.core.project$load_plugins.invokeStatic (project.clj:774)
    leiningen.core.project$load_plugins.invoke (project.clj:758)
    leiningen.core.project$load_plugins.invokeStatic (project.clj:775)
    leiningen.core.project$load_plugins.invoke (project.clj:758)
    leiningen.update_in$update_project.invokeStatic (update_in.clj:21)
    leiningen.update_in$update_project.invoke (update_in.clj:16)
    leiningen.update_in$update_in.invokeStatic (update_in.clj:37)
    leiningen.update_in$update_in.doInvoke (update_in.clj:24)
    clojure.lang.RestFn.applyTo (RestFn.java:146)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.main$partial_task$fn__7356.doInvoke (main.clj:284)
    clojure.lang.RestFn.applyTo (RestFn.java:139)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:31)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.main$apply_task.invokeStatic (main.clj:334)
    leiningen.core.main$apply_task.invoke (main.clj:320)
    leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:343)
    leiningen.core.main$resolve_and_apply.invoke (main.clj:336)
    leiningen.update_in$update_in.invokeStatic (update_in.clj:37)
    leiningen.update_in$update_in.doInvoke (update_in.clj:24)
    clojure.lang.RestFn.applyTo (RestFn.java:146)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.main$partial_task$fn__7356.doInvoke (main.clj:284)
    clojure.lang.RestFn.applyTo (RestFn.java:139)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:31)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$apply.invoke (core.clj:660)
    leiningen.core.main$apply_task.invokeStatic (main.clj:334)
    leiningen.core.main$apply_task.invoke (main.clj:320)
    leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:343)
    leiningen.core.main$resolve_and_apply.invoke (main.clj:336)
    leiningen.core.main$_main$fn__7445.invoke (main.clj:453)
    leiningen.core.main$_main.invokeStatic (main.clj:442)
    leiningen.core.main$_main.doInvoke (main.clj:439)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.main$main_opt.invokeStatic (main.clj:491)
    clojure.main$main_opt.invoke (main.clj:487)
    clojure.main$main.invokeStatic (main.clj:598)
    clojure.main$main.doInvoke (main.clj:561)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.main.main (main.java:37) 

The issue comes from this piece of code which seems not to be evaluated when the file is not compiled:

(defconst sayid-version
  (eval-when-compile
    (lm-version (or load-file-name buffer-file-name)))
  "The current version of `clojure-mode'.")

as a result the variable is empty and:

;;;###autoload
(defun sayid--inject-jack-in-dependencies ()
  "Inject the REPL dependencies of sayid at `cider-jack-in'.
If injecting the dependencies is not preferred set `sayid-inject-dependencies-at-jack-in' to nil."
  (when (and sayid-inject-dependencies-at-jack-in
             (boundp 'cider-jack-in-lein-plugins)
             (boundp 'cider-jack-in-nrepl-middlewares))
    (add-to-list 'cider-jack-in-lein-plugins `("com.billpiel/sayid" ,sayid-version))
    (add-to-list 'cider-jack-in-nrepl-middlewares "com.billpiel.sayid.nrepl-middleware/wrap-sayid")))

adds an empty value into cider-jack-in-lein-plugins which subsequently fails the call to leiningen or clojure repl.

When I replace the variable with:

(defconst sayid-version
  "0.1.0"
  "The current version of `clojure-mode'.")

Then the issue seems to be gone. I'll try to find a workaround for this in spacemacs.

@smile13241324 Thanks for your feedback!
BTW: Which file are you modifying? Maybe I can lend a hand...

@allentiak I was directly in the sayid package. Sayid-version is a function as well as a variable where the variable is defined by analysing the package path, this however seems to only work when the file is either compile or evaluated manually. If it is loaded by use-package it seems to stay nil. We could try to force the package to evaluate this variable in our use-package init-sayid as a workaround.

If you could build up a minimalistic case where one can see that the package does not correctly load when run by use-package (still a theory by now) and open a ticket upstream this would help a lot.

@smile13241324 Wow. I didn't expect to find a bug upstream!
I've just opened clojure-emacs/sayid#60.

I think we need to reproduce that behaviour with use-package, until now this is still a theory. Personally I would have preferred to reproduce it before we open a ticket upstream, nevertheless now that we have one open, lets try to analyse that case next.

I can invest some time into this in the next view days.

Ok, I have found the trigger, I am not sure why it is happening though. Simply spoken it is not use-package but the package installation that is the problem. When the package is compiled during the installation the byte code contains the following line:

;ELC�\0\0\0
;;; Compiled
;;; in Emacs version 27.1
;;; with all optimizations.

;;; This file uses dynamic docstrings, first added in Emacs 19.29.

;;; This file does not contain utf-8 non-ASCII characters,
;;; and so can be loaded in Emacs versions earlier than 23.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(byte-code "\300\301!\210\300\302!\210\303\304\305\306\307\310\311\312\313\314\313\315\313\316&
\210\317\320\321\322\311\304\323\324&�\207" [require lisp-mnt cider custom-declare-group sayid nil "Sayid is an advanced Clojure debugging tool." :prefix "sayid-" :group applications :link (url-link :tag "GitHub" "https://github.com/clojure-emacs/sayid") (url-link :tag "Online Manual" "http://clojure-emacs.github.io/sayid") (emacs-commentary-link :tag "Commentary" "sayid") custom-declare-variable sayid-inject-dependencies-at-jack-in t "When nil, do not inject repl dependencies (most likely nREPL middlewares) at `cider-jack-in' time." :type boolean] 14)
#@40 The current version of `clojure-mode'.�
(defconst sayid-version nil (#$ . 1063))

Notice that sayid-version is defined as nil.
As a result the variable is always nil, as the compiled version is always preferred. When the .el file is loaded instead it works flawlessly.

It works the first time as the compile version has not yet been read I assume. With the next restart however the .elc file is loaded with nil in there. When the file is compiled interactively it also produces the right byte code. If the entire clojure layer is reinstalled it is also properly installed.

I think I need to take a deep dive into the Spacemacs package installation process to understand this issue.

I think I need to take a deep dive into the Spacemacs package installation process to understand this issue.

From the feedback I got in clojure-emacs/sayid#60 (comment), it definitely seems a Spacemacs-related problem...

@allentiak I think I have found a workaround for this issue on develop. Care to give it a try on latest develop?

@smile13241324 I've just tested it. It works :-)

Thanks for your hard work, @smile13241324 !