Skip to content
This repository

Incomplete forms with trampoline on Windows #674

Closed
vasilism opened this Issue July 03, 2012 · 11 comments

7 participants

vasilism Phil Hagelberg Tzach Livyatan John Wang Nick Klauer Bill Robertson danjohansson
vasilism

$ operating system
Windows 7

$ lein version
Leiningen 2.0.0-preview7 on Java 1.7.0_04 Java HotSpot(TM) Client VM

$ lein repl
nREPL server started on port 49766
REPL-y 0.1.0-beta8
Clojure 1.3.0
user=> (exit)

$ lein trampoline repl
Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.RuntimeException: EOF while reading, starting at line 1
at clojure.lang.LispReader.read(LispReader.java:215)
at clojure.core$read.invoke(core.clj:3346)
at clojure.core$read.invoke(core.clj:3344)
at clojure.main$eval_opt.invoke(main.clj:295)
at clojure.main$initialize.invoke(main.clj:316)
at clojure.main$script_opt.invoke(main.clj:340)
at clojure.main$main.doInvoke(main.clj:427)
at clojure.lang.RestFn.invoke(RestFn.java:3659)
at clojure.lang.Var.invoke(Var.java:518)
at clojure.lang.AFn.applyToHelper(AFn.java:388)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: EOF while reading, starting at line 1
at clojure.lang.Util.runtimeException(Util.java:170)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1117)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:962)
at clojure.lang.LispReader.read(LispReader.java:180)

Tzach Livyatan
tzach commented July 14, 2012

Same problem on Windows 7
Leiningen 2.0.0-preview7 on Java 1.6.0_20 Java HotSpot(TM) Client VM

More from the bottom of the stack trace:
'args]' is not recognized as an internal or external command,
operable program or batch file.
'args]' is not recognized as an internal or external command,
operable program or batch file.

John Wang

I'm stuck on the same problem.
Window 7 / Leiningen 2.0.0-preview7

Nick Klauer

This happens on Win7 / lein2.0.0-preview8 as well:

> lein trampoline run
Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.RuntimeException: EOF while reading, starting at line 1
        at clojure.lang.LispReader.read(LispReader.java:215)
        at clojure.core$read.invoke(core.clj:3346)
        at clojure.core$read.invoke(core.clj:3344)
        at clojure.main$eval_opt.invoke(main.clj:295)
        at clojure.main$initialize.invoke(main.clj:316)
        at clojure.main$script_opt.invoke(main.clj:340)
        at clojure.main$main.doInvoke(main.clj:427)
        at clojure.lang.RestFn.invoke(RestFn.java:3894)
        at clojure.lang.Var.invoke(Var.java:527)
        at clojure.lang.AFn.applyToHelper(AFn.java:410)
        at clojure.lang.Var.applyTo(Var.java:532)
        at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: EOF while reading, starting at line 1
        at clojure.lang.Util.runtimeException(Util.java:170)
        at clojure.lang.LispReader.readDelimitedList(LispReader.java:1117)
        at clojure.lang.LispReader$ListReader.invoke(LispReader.java:962)
        at clojure.lang.LispReader.read(LispReader.java:180)
        ... 11 more
Bill Robertson

Same problem with preview 10. After poking around a bit, I discovered that lein writes a trampoline .bat file out and then calls that and then deletes it. I changed my lein2.bat to not delete the file after it runs so I could see what's going on.

The end of generated bat file looks like this:

...
"clojure.main" "-e" ""(do (clojure.core/require (quote clojure.tools.nrepl.server) (quote complete.core) (quote reply.main)) (set! warn-on-reflection nil) (reply.main/launch-nrepl {:custom-init nil, :port \"0\"}))""

I assume that the -e argument followed by some lisp in the bat file is telling clojure.main to run a one-liner. Notice that the one liner is double-quoted twice. Running this file as-is produces the bad behavior. I deleted the extra set of quotes around the one liner, and reran the .bat file and it the repl starts.

...
"clojure.main" "-e" "(do (clojure.core/require (quote clojure.tools.nrepl.server) (quote complete.core) (quote reply.main)) (set! warn-on-reflection nil) (reply.main/launch-nrepl {:custom-init nil, :port \"0\"}))"

I've looked at trampoline.clj a tiny bit, but its not really clear to me where the extra quotes are coming from. I'm sure the fix for this is easy if you already know the right place to apply it.

As a short term work around, I guess you could keep a trampoline bat file around for each trampoline task you want to run, and regenerate it if your project changes.

Phil Hagelberg
Owner

Probably caused by this workaround for a Windows Java bug: https://github.com/technomancy/leiningen/blob/master/leiningen-core/src/leiningen/core/eval.clj#L144

I guess we need to check for trampolining before applying the workaround.

Phil Hagelberg technomancy closed this in 8c68621 August 30, 2012
Phil Hagelberg
Owner

Let me know if this doesn't address the issue.

Bill Robertson

Not really sure how to test it just yet. Looking at the code though, I wonder if it wouldn't be best in the windows case to just check to see if the string is already quoted before quoting. e.g. (if (and windows (not (quoted? string)) (str "\"" string "\"") string). I don't think my string quoting is right, but I hope I'm getting the idea across.

Phil Hagelberg
Owner

The double-quoting is actually intentional; it's a workaround for a bug in the Windows version of the JDK: http://bit.ly/9c6biv

But since trampoline doesn't use the JDK to launch the process it gets in the way.

Bill Robertson

Makes perfect sense.

danjohansson

Hi
I have had problems with this as well.
The fix do not work as :eval-in :trampoline is not set in the project argument. Below is a fix for that.
There is also a fix that stopped me from getting lein trampoline cljsbuild repl-listen to work. Seems related to the quoting issues. But the fix here may break something else?

Also I discovered another (known?) windows problem that is not fixed here and should probably be reported as a separate issue. The error can be similar to the one reported on this issue though. The problem is that the trampoline file can get to big. The limit is 8191 and that is easily reached especially if the path to your deps is long.

These fixes are not well tested and just added here to easily explain my findings.
Edit: The changes were made on the preview branch + commit 8c68621.

I use win7 and java 1.6.0_31

diff --git a/src/leiningen/trampoline.clj b/src/leiningen/trampoline.clj
index ccba2d9..a03cc32 100644
--- a/src/leiningen/trampoline.clj
+++ b/src/leiningen/trampoline.clj
@@ -9,6 +9,8 @@

 (def ^:dynamic *trampoline?* false)

+(defmacro dbg[x] `(let [x# ~x] (println '~x "=" x#) x#))
+
 (defn- win-batch? []
   (.endsWith (System/getProperty "leiningen.trampoline-file") ".bat"))

@@ -25,11 +27,10 @@
         project (project/normalize-deps (assoc project :dependencies
                                                (apply concat deps)))
         command (eval/shell-command project (concat '(do) inits rests))]
+ ;;I get errors like java.lang.RuntimeException: Unable to resolve symbol: 
+ ;;.lein-cljsbuild-repl when the special windows handling is enabled.
-    (string/join " " (if (win-batch?)
-                       (map quote-arg command)
-                       (conj (vec (map quote-arg (butlast command)))
-                             (with-out-str
-                               (prn (last command))))))))
+
+    (dbg (string/join " " (conj (vec (map quote-arg (butlast command)))
+                                (with-out-str
+                                  (prn (last command))))))))

 (defn write-trampoline [project forms deps]
   (let [command (trampoline-command-string project forms deps)
@@ -49,12 +50,13 @@ 
   [project task-name & args]
   (when (= :leiningen (:eval-in project))
     (main/info "Warning: trampoline has no effect with :eval-in-leiningen."))
-  (binding [*trampoline?* true]
-    (main/apply-task (main/lookup-alias task-name project)
-                     (-> (assoc project :eval-in :trampoline)
-                         (vary-meta update-in [:without-profiles] assoc
-                                    :eval-in :trampoline))
-                     args))
-  (if (seq @eval/trampoline-forms)
-    (write-trampoline project @eval/trampoline-forms @eval/trampoline-deps)
-    (main/abort task-name "did not run any project code for trampolining.")))
+ ;; Without this change the fix for Issue #674 wont work
+  (let [project (-> (assoc project :eval-in :trampoline)
+                  (vary-meta update-in [:without-profiles] assoc
+                             :eval-in :trampoline))]
+    (binding [*trampoline?* true]
+      (main/apply-task (main/lookup-alias task-name project)
+                       project
+                       args))
+    (if (seq @eval/trampoline-forms)
+      (write-trampoline project @eval/trampoline-forms @eval/trampoline-deps)
+      (main/abort task-name "did not run any project code for trampolining."))))
danjohansson

Noticed another thing as well. With the changes above it is possible to trampoline in git bash on windows. That did not work before. You can use bash as a workaround for the 8192 limitation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.