Fork me on GitHub
#boot
<
2016-12-29
>
vikeri08:12:27

How do I pass verbose to boot in the repl? Not (boot “-v” “build”) nor (boot :verbose true (build)) works for me.

pesterhazy08:12:06

@vikeri rebind *verbose* I think

pesterhazy08:12:32

util/*verbosity* actually

pesterhazy08:12:50

(with-binding [util/*verbosity* 1] (boot ...))

pesterhazy08:12:28

it should be a number 🙂

vikeri08:12:37

(reset! boot.util/*verbosity* 3) (boot (build)) worked

pesterhazy08:12:08

ah it's an atom yes, confusingly

lwhorton17:12:22

Hey guys I’m going to repost this here since I think it’s more of a boot question than clojure:

lwhorton17:12:24

I’m stuck on a way to return a symbol from a fn… if that’s even the right strategy. The pandeiro/boot-http lib for http-proxying accepts a :handler ‘my.app/some-ring-handler argument (a symbol). If I wanted to do something like

...
(boot-http/serve :handler (make-proxy “/my-api/” “”)
...
I would need to return a symbol for serve. How does one generate a function inside a function, and instead of returning the generated function, return a symbol for that function? Is this totally incorrect?

geoffs17:12:56

I think it might be better to back up. what is the point of calling make-proxy in your build.boot file?

geoffs17:12:21

Does the call to make-proxy change based on which task you're running?

lwhorton17:12:51

indeed, I may want to proxy to dev.myuri or prod.myuri, etc.

lwhorton17:12:05

I just want to be able to provide arguments from a boot file to my proxyer

lwhorton17:12:06

for example

...
    (serve :dir "target"
           :port 9000
           :handler (make-proxy {:uris-to-proxy "/v1"
                                 :proxy-target “}))

lwhorton17:12:50

but I may want to run another task that does a :proxy-target to :

lwhorton17:12:08

I would expect the :handler to accept either a var, or a symbol, or a function, but it seems to only take a symbol… and I’m wondering if there’s a way to pass args through in that case

geoffs17:12:05

hmm. the simple option would be to make a var (i.e. (def proxy1 ...) for each proxy target and then reference those vars. And I would put those vars into the same ns that your main ring handler is in

geoffs17:12:13

I'm not positive about how boot-http works, but it may take a symbol because of using a pod internally, so it wouldn't be able to ship a var or a function to where it needs to be

micha17:12:45

there is an experimental macro since 2.6.0 btw, that lets you ship almost anything to a pod

lwhorton17:12:45

I see … that’s a bummer but I did get to learn about clojure sym/var lookup and binding steps 🙂

micha17:12:56

boot.pod/with-pod

geoffs18:12:06

oh, interesting

micha18:12:20

you can do interesting things like

micha18:12:31

(def p (make-pod boot.pod/env))
(def x 100)
(defn doit [y] (+ x y))

(with-pod p (def z 200))
(with-pod p (~doit z))

micha18:12:38

it's not super efficient though, because it uses reflection extensively

micha18:12:03

but sometimes you don't need efficiency because you're not doing a lot of it

lwhorton18:12:06

that sounds like a whole ‘nother layer I need to investigate … and away we go

micha18:12:29

also it hooks into implementation details of clojure so there needs to be some way to choose the correct implementation for the version of clojure in use

micha18:12:37

but pods can use a different version of clojure....

micha18:12:57

basically it's alpha currently 🙂

geoffs18:12:16

still, pretty neat

micha18:12:03

that's where it's implemented currently

geoffs18:12:21

@lwhorton I don't think with-pod really help your specific issue. It's more going to be helpful if you wrote your own tasks and ship arbitrary stuff into a pod

geoffs18:12:47

So, I hestitate to mention this because it's kind of a bad practice in general... but @lwhorton you could also write make-proxy so that it defs a new global var and then returns that var.

richiardiandrea18:12:50

@micha so can with-pod avoid ad-hoc serialization of stuff like Exceptions?

micha18:12:13

@richiardiandrea yes, except for ex-infos

micha18:12:24

it passes java objects veratim

richiardiandrea18:12:27

ok lol the only case I needed 🙂

micha18:12:44

it might not be difficult to add support for that though

geoffs18:12:09

Something like this @lwhorton:

(defn make-proxy [args]
  (def proxy (-> actual.ns.of.var/routes (wrap-proxy args)))
`proxy)

micha18:12:17

one approach i was using is if the clojure type has a constructor that takes a java object

micha18:12:27

then use reflection to construct it

micha18:12:54

it might need to be wrapped though

lwhorton18:12:01

thanks @geoffs thats what i initially tried but it just smells really dangerous

micha18:12:10

like treat the ex-info from the pod as the cause of the ex-info that is returned

micha18:12:18

because that's a Throwable

micha18:12:35

and use reflection to copy the info to the wrapper ex-info

richiardiandrea18:12:15

@micha Deraen implemented a neat solution using proxy, I don't know if you have seen it

geoffs18:12:18

@lwhorton yeah, good instincts 🙂 I would definitely prefer to make a var per proxy needed

micha18:12:37

@richiardiandrea do you have a link handy?

micha18:12:02

@lwhorton i think the issue is that the symbol must be resolvable in the pod

micha18:12:07

the pod that boot-http makes

richiardiandrea18:12:41

not complete but working for inter-pod ex-info passing

micha18:12:06

@lwhorton i think your best bet is to make a namespace that is on the pod's classpath with your handler fn in there

richiardiandrea18:12:26

maybe I will reopen that issue just to keep track of it

richiardiandrea18:12:45

both boot-cljs and the future boot-reload need this so it might be worth implementing

micha18:12:42

the interesting thing is that java objects that are loaded from a shared parent classloader (like Throwables) don't necessarily need to be serialized

micha18:12:02

they can be passed to the caller pod as is

micha18:12:19

the only part that needs to be dealt with is the clojure subtype stuff

micha18:12:22

like the info

micha18:12:30

and the info can be serialized

micha18:12:59

so it would be possible to wrap the ex-info Throwable as the cause of a new ex-info in the caller pod

richiardiandrea18:12:29

I think this already happens, if I read the code right...

richiardiandrea18:12:07

and I tried without Deraen's trick (so pure ex-info stuff) but it fails

richiardiandrea18:12:55

the error was that no reader tag was found (I guess for #error ?)

juhoteperi18:12:05

is parent classloader same as the "root pod"?

juhoteperi18:12:18

or is that the classloader used by Boot binary?

micha18:12:45

all the pods are "siblings", meaning they all share the same parent classloader

micha18:12:50

which is the java one

juhoteperi18:12:59

so it doesn't contain Clojure classes?

micha18:12:01

the parent will resolve all the java stdlib classes

micha18:12:12

no, if it ever does then pods will no longer work

micha18:12:27

classloaders resolve classes from the top down

micha18:12:39

meaning parent first, then child if parent can't find the class

micha18:12:15

the parent must never know about any clojure classes

micha18:12:22

that's why we need Boot.java

micha18:12:45

the bootstrapping code needs to be clojure-free

juhoteperi18:12:26

Hmm, Clojure version is same for every pod... but Clojure contains some global state which must not be shared?

richiardiandrea18:12:28

uhm, so when we pass stuff between pod we are basically executing code in Java land only...makes sense then

richiardiandrea18:12:39

Clojure version can be different in pod right?

micha18:12:41

clojure version can be different for different pods

micha18:12:54

the issue is with the dynamic nature of clojure

juhoteperi18:12:59

Oh. Though I guess it usually is the same.

micha18:12:10

many of the clojure classes and interfaces are created dynamically at runtime

micha18:12:30

so they're essentially gensyms as far as java is concerned

micha18:12:43

like names in one pod do not correspond to the same objects as names in another pod

micha18:12:04

including names like PersistentArrayMap or whatever

micha18:12:13

or any of the protocols

micha18:12:41

with-pod almost works with ex-infos

micha18:12:44

boot.user=> (.getMessage (with-pod p (ex-info "asdf" {:a 1})))
"asdf"

micha18:12:58

because it's returning a RuntimeException

micha18:12:13

of course it doesn't implement IExceptionInfo in the calling pod

micha18:12:31

it implements the IExceptionInfo interface in the callee pod

micha18:12:37

so this doesn't work

micha18:12:45

boot.user=> (ex-data (with-pod p (ex-info "asdf" {:a 1})))
nil

micha18:12:19

is there such a thing as specify! in clojure?

richiardiandrea18:12:21

so we need a custom exception with the data stuff serialized to Java objects basically

micha18:12:23

that's what we want here

micha18:12:44

we just need to implement that interface on an existing object

micha18:12:48

in the caller pod

micha18:12:15

proxy makes a new object, which we want to avoid

richiardiandrea18:12:25

uhm I don't think so..

micha18:12:01

yeah probably impossible on the jvm

richiardiandrea18:12:28

oh it's monkey patching again, I have never used it in cljs 😉

monjohn18:12:47

Don’t know if something is corrupted but every boot command I try results in

Downloading ...
Exception in thread "main" java.io.FileNotFoundException: 
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1836)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
	at java.net.URL.openStream(URL.java:1038)
	at Boot.download(Boot.java:173)
	at Boot.install(Boot.java:224)
	at Boot.main(Boot.java:243)

lwhorton18:12:55

thanks @micha I’ll look into that

micha18:12:47

@monjohn can you please do cat ~/.boot/boot.properties?

micha18:12:52

and paste

monjohn18:12:53

@micha That explains it:

BOOT_CLOJURE_NAME=org.clojure/clojure
BOOT_VERSION=show
BOOT_CLOJURE_VERSION=1.7.0

micha18:12:13

if you just delete that file

micha18:12:27

it's trying to download boot version "show", which isn't a real version

micha18:12:45

not sure how that got in there but you can delete the file and should work

monjohn18:12:23

@micha Thanks for your help!

neupsh23:12:21

hi, when i write a namespace with gen-class, and run boot with boot aot repl, and try to import the class declared in the gen-class, it fails with ClassNotFound but the same thing works if i try to load in a lein repl:

micha23:12:04

@nux is the class on the classpath? like ( "bt/MyArrayList.class") returns non-nil?

neupsh23:12:02

@micha hello micha, i can see the class file created in the target directory, so it should be, let me run it and see

neupsh23:12:48

it returned nil

micha23:12:58

interesting

micha23:12:03

in the repl, what if you do this:

micha23:12:40

boot.user=> (boot (aot :namespace '#{bt.core}))

micha23:12:50

and then try again?

micha23:12:57

which version of boot are you using?

neupsh23:12:19

@micha it worked now, it is 2.7.1

micha23:12:37

so with any version of boot >= 2.6.0 the target dir is not written by default

micha23:12:46

it only is wrtten when you use the target task

micha23:12:00

so what you see in the target dir must be old, from a previous build

micha23:12:56

it seems that the directory where the aot task put the compiled class file

micha23:12:04

that directory is not on the classpath of the repl somehow

richiardiandrea23:12:49

@juhoteperi is there a way for boot-reload to know the compiler options when there is no .cljs.edn file and boot-cljs has not be triggered yet (aka, before the call to (next-task fileset) ?

micha23:12:12

there is always a .cljs.edn file

micha23:12:23

it is autogenerated if necessary

richiardiandrea23:12:37

no if boot-cljs has yet to run

richiardiandrea23:12:04

yeah I am exactly banging my head against this case

micha23:12:20

why does reload care about compiler options?

richiardiandrea23:12:22

figwheel creates the init script based on compiler opts

richiardiandrea23:12:45

old boot-reload cleverly does not 😉

micha23:12:53

yeah don't do that 🙂

neupsh23:12:48

@micha so now it worked, i was actually testing for a weird problem i am facing

neupsh23:12:05

i am trying to subclass a class from jnr-fuse library, and i have the gen-class on the namespace. it can be imported well as well, but when i try to instantiate the class, it fails with classNotFound on something else (some class from the library). weird thing is i can instantiate the superclass i am overriding just fine in the repl

micha23:12:54

^^ this seems like the class reloading issue

micha23:12:04

there is a pull request with a task, i believe

micha23:12:23

hm it's for the javac task

richiardiandrea23:12:09

@juhoteperi @micha there is also another problem with the current approach: there can be only one on-jsload per boot-reload execution, as opposed to one on-jsload per build - see here https://github.com/adzerk-oss/boot-reload/blob/master/src/adzerk/boot_reload.clj#L128

richiardiandrea23:12:39

but ok that is more like the way boot-reload differs from figwheel in general

neupsh23:12:53

@micha is there a way to get around the issue? or actually figuring out what is going on there.. its weird that i can instantiate the class i am subclassing but it throws exception for the generated class. for example, i am subclassing the ru.serce.jnrfuse.FuseStubFS class which uses jnr-ffr library, when i do (def a (FuseStubFS.)) after the import, i get no error, but when i do (def b (MyExtendingClass. )) it throws error (even with nothing added, just subclassing it). `java.lang.ClassNotFoundException: jnr.ffi.provider.jffi.NativeClosureProxy java.lang.NoClassDefFoundError: jnr/ffi/provider/jffi/NativeClosureProxy java.lang.RuntimeException: java.lang.NoClassDefFoundError: jnr/ffi/provider/jffi/NativeClosureProxy`

neupsh23:12:20

and those are all in the library loaded in the classpath

neupsh23:12:58

i can import jnr.ffi.provider.jffi.NativeClosureProxy just fine in the repl

richiardiandrea23:12:40

the above can be solve by having a more complex option like: j on-jsload ID=SYM {str sym} "The callbacks to call when JS files are reloaded. (optional)"