Fork me on GitHub
#boot
<
2017-01-30
>
podviaznikov00:01:36

hey guys, I have CLJS single page app and using boot. I have API endpoint I hit and it’s defined like this

(def API_URL “)
. How do I define it differently for the production? My boot file looks like this
(deftask build []
  (comp (speak)
        (cljs)))
(deftask production []
  (task-options! cljs {:optimizations :advanced})
  identity)

richiardiandrea00:01:18

you could to:

(deftask build []
  (comp (speak)
        (cljs)))
(deftask production []
  (task-options! cljs {:optimizations :advanced})
  (build))

podviaznikov00:01:09

Yeah, but can I specify different API_URL for production?

micha00:01:22

@grounded_sage CLJ and CLJS in boot use the same JVM, but likely different pods

micha00:01:29

depending on how you do things

richiardiandrea00:01:06

@podviaznikov oh ok I did not notice that var above, so probably you need some dynamic var magic

richiardiandrea00:01:32

(def ^:dynamic *api_url* ")

(deftask build []
  (comp (speak)
        (cljs)))
(deftask production []
  (binding [*api-url* something]
    (task-options! cljs {:optimizations :advanced})
    (build)))

micha00:01:00

@grounded_sage it's not possible (yet) to actually share an atom across pods, but you can share for instance a java.util.concurrent.ConcurrentHashMap

richiardiandrea00:01:15

@podviaznikov if you want to keep things this way, but there are many ways to handle it, you can make a let inside each task, dev and production, or pass a parameter

richiardiandrea00:01:41

tbh :dynamic is the solution I like less

grounded_sage00:01:15

@micha so best thing to do would be to use enduro to put it into a file. Is there a way to put it in at the end of Clojure compilation and pull it back out at start of CLJS compilation. Just thinking that writing every change to disk will be slow.

micha00:01:49

@grounded_sage can you describe...oh ok

micha00:01:03

one thing you can do is stuff info into a system property

micha00:01:13

that is a real easy way to pass stuff around JVM-wide

micha00:01:27

it would need to be serialized of course, but that's probably no problem

micha00:01:11

i don't know how thread-safe writing to system properties is, but i imagine it would be easy to use some locking or whatever

grounded_sage00:01:33

Generating atomic css classes. So the issue I have is that I generate the styles and corresponding classes. During CLJ it renders Rum to static HTML with the Class names. But when it renders the client side Rum it starts fresh with a new atom and creates different class names. Due to the compilation difference I end up with a miss match of class names on html elements client side. cc @micha

richiardiandrea00:01:18

@podviaznikov I am kind of afraid to show this to people 🙂 but in lambone I use multi-methods for that, and the concept of "flavor", which is a string I pass from the command line: https://github.com/Lambda-X/lambone/blob/master/resources/leiningen/new/lambone/common/build.boot#L101

micha00:01:09

@grounded_sage so you need to share a map between clj and cljs?

grounded_sage00:01:57

Yea pretty much.

micha00:01:07

i recommend using a system property

micha00:01:24

i do this in a cache-busting library i wrote

micha00:01:43

i wanted to go the other way, like the inverse of what you're doing, but it would work the same

micha00:01:41

like i wanted to be able to do this in my hoplon app:

(style :href (cache-bust "css/main.css") :rel "stylesheet")

micha00:01:08

where it would incorporate a cache-busting hash into the link

micha00:01:31

but then a boot task (in CLJ land) would know that it has to rename that file and use the precomputed hash

micha00:01:47

i used a system property for that

micha00:01:00

i set the system property in the macro

micha00:01:09

and read it in the boot task

micha00:01:15

but you could of course go the other way

grounded_sage00:01:22

Should I use this library? https://github.com/weavejester/environ or is it easy to just set it with some interop or something?

micha00:01:46

(System/setProperty "FOOP" "barp")

micha00:01:01

(def barp (System/getProperty "FOOP"))

micha00:01:06

no need for libraries for that

grounded_sage00:01:28

Cool cool. That's what I thought. Felt like a library would be overkill.

micha00:01:49

the only thing is that key and value must be strings

micha00:01:03

so you will need to pr-str or something

micha00:01:10

and read-string

grounded_sage00:01:38

Thanks. I'll give it a crack sometime today and see if it resolves the issue I am having.

lxsameer12:01:57

hi, is it possible to have a run task which uses two different pods ( one for clj, and one for cljs ) to run a clojure and clojurescript application ?

micha12:01:20

boot.pod/make-pod

juhoteperi14:01:50

Hmm, do we have any examples of boot-in-pod, for testing?

juhoteperi14:01:08

boot.core/boot is not available inside pods but is there some other way to run boot inside tests?

micha14:01:19

@juhoteperi you can call boot.App/runBoot from anywhere

juhoteperi14:01:37

Hmm, but that one needs the tasks as command like string args

micha14:01:17

right, it will be a separate boot invocation basically, but in the same jvm

juhoteperi14:01:21

Only things boot.core/boot really do are to create fileset (and setup fileset sync, which I don't need) and run the task pipeline with the fileset

juhoteperi14:01:41

So I think I should only need a way to create fileset, and run it with my pipeline function

juhoteperi14:01:09

For testing, it might make sense to completely mock the fileset

juhoteperi14:01:24

Then I don't need to include the test files in application classpath at all

micha14:01:33

interesting

juhoteperi14:01:44

boot.tmpdir is available from pod so should be doable

micha14:01:39

@juhoteperi there is a function in boot.core for creating a new fileset

micha14:01:49

it's pretty small

juhoteperi14:01:01

Yep, I'm just re-creating it for my usecase

juhoteperi15:01:08

Eh, picard-facepalm I can't require the task namespaces as those require boot.core

micha15:01:29

i am working on refactoring that stuff

micha15:01:08

factoring out the stateful parts of boot.core

juhoteperi15:01:13

also, the global env is a bit impractical here

micha15:01:21

yeah i want to get away from that

juhoteperi15:01:21

should make this easier

juhoteperi15:01:47

also I'm not sure how far I can get with testing boot-cljs as Cljs does use classpath

juhoteperi15:01:58

@richiardiandrea That would probably work, but I was hoping I could just call boot in normal deftest and check the results

juhoteperi15:01:46

It'll make the testing easier if I can mock away all the state (deps, classpath, watch task...)

richiardiandrea15:01:55

I had the same problem I think while doing it and decided to take this other way together with micha 😀

juhoteperi15:01:15

Hmm, I should be even able to "mock" or control classpath with Thread.setContextClassLoader

juhoteperi15:01:18

I just wonder if new threads inherit current context class loader

juhoteperi15:01:53

> A thread's context class loader is, by default, set to the context class loader of the thread's parent.

juhoteperi15:01:57

should work...

juhoteperi15:01:02

but future & co use existing thread pool so those won't inherit my context class loader

richiardiandrea15:01:07

Yeah @juhoteperi unless you hook a ThreadFactory I guess?

lxsameer15:01:27

I'm looking for some pods example

lxsameer15:01:36

do you know any ?

lxsameer16:01:11

@micha I already read that, I need some real examples

juhoteperi16:01:18

@lxsameer less4clj should be quite simple: https://github.com/Deraen/less4clj/blob/master/boot-less/src/deraen/boot_less.clj#L64-L67, a pod with one extra dependency and one with-eval-in

lxsameer16:01:53

hmmm, I want to have a task called run, Invoking it should run several tasks under pod A and several other tasks under pod B

lxsameer16:01:05

I have this in mine, is it correct ?

micha16:01:24

tasks should run in the main pod, not in different pods

lxsameer16:01:25

(def pod-a (future (make-pod ....)))
(def pod-b (future (make-pod ....)))

(deftask run
....
(with-eval-in @a (cljs-tasks))
(with-eval-in @b (clj-tasks)))

micha16:01:34

a task may do work in a pod

micha16:01:49

but the task pipeline is all in the same pod

micha16:01:03

like the boot-less example

micha16:01:14

the task itself is running in the core pod

micha16:01:22

(the pod build.boot is evaluated in)

micha16:01:31

but it constructs a pod in which to do work

micha16:01:31

you can create a pod with variouus maven dependencies, and then you can eval expressions in that pod

lxsameer16:01:20

is my code concept is correct ?

micha16:01:52

what is cljs-tasks?

micha16:01:26

the boot.core namespace, for example, cannot be loaded into a pod

lxsameer16:01:39

really ? why ?

micha16:01:47

because it needs to be a singleton, it's stateful and not thread-safe

micha16:01:55

because it needs to manipulate the filesystem etc

lxsameer16:01:12

@micha let me tell you my main problem then

lxsameer16:01:13

@micha I'm trying to fire up both clj and cljs environment in the same task, and since I'm using Sente, and it has some weird bug with reloading and clojure.tools.namespace.repl

lxsameer16:01:23

I can not to that.

lxsameer16:01:49

so I'm looking for a solution to run them side by side but without any effect to each other

juhoteperi16:01:28

Now I have Agent/soloExecutor set so that future sees the changed context class loader, but now I fear that pods might not inherit context class loader 😄

juhoteperi16:01:06

I'm using tools.namespace fork for now

lxsameer16:01:27

@juhoteperi do you do the same thing as I'm doing ? ( I mean clj and cljs together )

lxsameer16:01:58

can I see your source code ?

juhoteperi16:01:05

You could try adding these deps to the project, though I can't really recommend using this:

;; FIXME: Need to depend on both, else some task or such
                  ;; might add old org.clojure/tools.namespace 0.2 version to a pod which contains
                  ;; clj files instead of cljc and those overwrite the new files.
                  ;; Fork is latter so it will overwrite files from original.
                  [org.clojure/tools.namespace "0.3.0-alpha3"]
                  [metosin.forks/tools.namespace "0.3.0-20160926.120815-2"]

lxsameer16:01:02

I meant the whole build.boot 😛

juhoteperi16:01:44

I don't think I have any public projects using this

lxsameer16:01:01

thanks any way 🙂

juhoteperi16:01:11

But except for those deps, the projects are very similar to https://github.com/Deraen/saapas/blob/master/build.boot#L64-L81

escherize17:01:57

Is there a surefire fix for that clout error when using compojure and boot?

escherize17:01:00

Exception in thread "main" java.lang.NoClassDefFoundError: clout/core/CompiledRoute

escherize17:01:49

I think I might have finally fixed it!

juhoteperi17:01:12

Well, I got quite near of mocking boot, fileset & classpath, but pods inherit App.class.getClassLoader() instead of context classloader and I can't find a way to override classpath for pods created by tasks

escherize17:01:24

Swapping the order of (uber) and using (aot :all true)

juhoteperi17:01:41

@escherize Yes, that looks like something that might be caused by AOT compilation

juhoteperi17:01:16

Compojure probably generates some code with macros that refers to that class and AOT compilation doesn't properly compile that namespace, or doesn't just include the compiled class files for some reason

richiardiandrea17:01:33

Wow @juhoteperi that's a hack 🙂 ^

richiardiandrea17:01:34

I wonder if your hack should replace the current boot.test, it probably should, and we could try if it works with that file I pasted above

juhoteperi17:01:36

Yeah, mocking fileset is easy enough but all that shared state in Clojure core and Boot makes that implementation really compilcated

juhoteperi17:01:14

@richiardiandrea It doesn't work yet, at least for Cljs, which uses classpath

richiardiandrea17:01:37

got it, just spreading ideas 😄 It looks interesting for sure

richiardiandrea17:01:04

my approach was no towards mocking stuff, but it is more cumbersome in a way...

lxsameer17:01:52

is it possible to invoke several task in parallel ? for example in a (future) ?

mobileink18:01:38

boot’s killing me again. my task is trying to read a string from an edn file in the fileset, and use it as the :dir param to the target task. I can’t get the string unless i use something like with-pre-wrap, but if I put the target task inside of that nothing happens. so i tried this:

mobileink18:01:40

(let [target-dir (atom "target")] (comp (boot/with-pre-wrap [fileset] ... get dir string from edn file ... (reset! target-dir dir) fileset) (builtin/target :dir #{@target-dir} :no-clean (or no-clean false))))

mobileink18:01:24

but it doesn’t take. @target-dir ends up as “target”, not the dir string. how can I make this work? thx.

pesterhazy18:01:36

(with-pre-wrap) needs to be wraped in a fn doesn't it? @mobileink

mobileink18:01:38

@pesterhazy : i don’t think so, that pattern works in my other tasks...

mobileink18:01:14

i omitted my (deftask … bit in that snippet, that’s where it is

juhoteperi18:01:50

@mobileink Not possible (at least cleanly), task options are set in a step before any handler core (code inside pre-wrap etc is run)

juhoteperi18:01:38

But it is possible to create new target task inside task that reads the edn file, in this case, the task will lose it's state (e.g. with cljs, the compiler state) but with target task this doesn't matter

mobileink18:01:46

what do you mean by “create new target task inside task that reads the edn file”? i tried to invoke builtin/target inside of with-pre-wrap, but nothing got written.

juhoteperi18:01:07

(defn read-edn-and-run-task []
  (fn middleware [next-handler]
    (fn handler [fileset]
      (let [{:keys [target-path]} (...read-edn fileset...)
            target-middleware (target :target target-path)
            target-handler (target-middleware next-handler)]
        (target-handler fileset)))))

juhoteperi18:01:19

target returns new middleware with the given option, target-middleware handler which can be called with a fileset and when finished, will call next-handler (what ever is after read-edn-and-run-task in the pipeline)

juhoteperi18:01:10

My recommendation is to not use pre/post-wrap, using middleware pattern directly makes it much easier to see what really happens

mobileink18:01:28

what is (target :target target-path)? do you mean (target :dir target-path)?

mobileink18:01:07

ok, i’ll give it a try. have always used pre/post-wrap, out of sheer laziness.

mobileink18:01:33

stack overflow. how do I use that kind of thing inside a deftask? it needs to be able to take params.

mobileink18:01:27

(defn read-edn-and-run-task [] (fn middleware [next-handler] (fn handler [fileset] (let [boot-config-edn-files (->> (boot/input-files fileset) (boot/by-name [boot-config-edn])) boot-config-edn-f (condp = (count boot-config-edn-files) 0 (do (util/info (str "Creating " boot-config-edn "\n")) (io/file boot-config-edn)) ;; this creates a java.io.File 1 (first boot-config-edn-files) ;; this is a boot.tmpdir.TmpFile (throw (Exception. (str "only one bootconfig.edn file allowed, found " (count boot-config-edn-files))))) boot-config-edn-map (if (instance? boot.tmpdir.TmpFile boot-config-edn-f) (-> (boot/tmp-file boot-config-edn-f) slurp read-string) {}) dir (str "target/" (-> boot-config-edn-map :module :name)) target-middleware (target :dir dir) target-handler (target-middleware next-handler)] (target-handler fileset))))) (boot/deftask target "target, using module name" [C no-clean bool "Don't clean target before writing project files" d dir DIR str "target dir" s servlet bool "building as servlet" v verbose bool "verbose"] (read-edn-and-run-task))

mobileink18:01:30

sorry make that

mobileink18:01:32

boot-config-edn-f (condp = (count boot-config-edn-files) 0 (throw (Exception. (str boot-config-edn " file not found"))) 1 (first boot-config-edn-files) ;; this is a boot.tmpdir.TmpFile (throw (Exception. (str "only one bootconfig.edn file allowed, found " (count boot-config-edn-files))))) boot-config-edn-map (-> (boot/tmp-file boot-config-edn-f) slurp read-string)

mobileink18:01:30

d’oh! it helps to call (builtin/target :dir dir) when you have a task also named target. now it works, thanks!

juhoteperi20:01:27

Wohoo, Boot-cljs now uses real class names for de-serialized exceptions from Cljs: https://github.com/boot-clj/boot-cljs/commit/1e840fabf63ec5b98f3caf67325e003fb766410c

richiardiandrea20:01:56

@juhoteperi if you push a SNAPSHOT I'll try it right away against boot-figreload as well 😉

richiardiandrea20:01:29

I am about to update it to 0.5.9, btw good job ^

juhoteperi20:01:38

Hmm, shouldn't happen

richiardiandrea20:01:53

let me clear the .m2 folder

pesterhazy20:01:15

isn't that fn missing a param vector? @richiardiandrea

richiardiandrea20:01:34

yep, I am triggering the error

juhoteperi20:01:49

Yeah, the problem is that the file path in exception message should be shorter

richiardiandrea20:01:26

thanks, I am going to remove it and see

juhoteperi20:01:01

Okay, I presume that the problem is in ex-parsing/parse-inspected-exception

richiardiandrea20:01:18

so @juhoteperi the whole thing is not necessary anymore?

juhoteperi20:01:51

@richiardiandrea exceptions use real classes instead of proxy, so there won't be those hideous class names anymore

richiardiandrea20:01:13

oh ok, that was a big deal when I first implemented it

juhoteperi20:01:08

But the problem with file path is probably that Figwheel logic selects the original :file property from some exception in cause stack, instead of the one that is processes by Boot-cljs

richiardiandrea20:01:16

trying again, I got rid of that regex

juhoteperi20:01:47

https://github.com/bhauman/lein-figwheel/blob/master/sidecar/src/figwheel_sidecar/cljs_utils/exception_parsing.clj#L80 this should select ex-data from the first exception that has tag analysis-error, and that should be the ex-info created by boot-cljs with correct filepath

richiardiandrea20:01:35

hum..it went even worse

juhoteperi20:01:27

hmm, send-visual! uses the serialized exception directly?

richiardiandrea20:01:39

yes but I had to adapt it

juhoteperi20:01:59

I think figwheel resumes that :class property has a real Class object

richiardiandrea20:01:27

that is why I needed to resolve the string there

juhoteperi20:01:30

you can take store (.getName (class e)) on serialization and resolve that

richiardiandrea20:01:12

so I used to do it for (re-find #"^adzerk.boot_cljs.util.proxy\$(.+)\$.+") now I need to do it all the time basically right?

juhoteperi20:01:54

It did it for every class before also

richiardiandrea20:01:13

uhm...ok need to check that part again, thanks for your help for now

richiardiandrea20:01:04

what I receive is:

{:exception {:class "clojure.lang.ExceptionInfo", :message "Parameter declaration \".info\" should be a vector at line 10, column 1 in file src/figreload_demo/core.cljs\n", :data {:file "src/figreload_demo/core.cljs", :line 10, :column 1, :tag :cljs/analysis-error, :from :boot-cljs, :boot.util/omit-stacktrace? true}, :cause ...}

juhoteperi20:01:27

That looks correct

richiardiandrea20:01:54

ok cool, so I'll continue from here, tnx

podviaznikov21:01:49

Hi guys, company (Runnable) starting to offer free service for few OS projects. We do staging env per commit. I set it up for perun. I can’t come up with use case for boot, but still wanted to check with you. If you think Runnable can be useful for boot - let me know

richiardiandrea21:01:42

and except for the first one we don't normalize paths in our stack traces

richiardiandrea21:01:01

shall we do it on our end (probably yes, but I have to do in boot-cljs)

richiardiandrea21:01:26

I'll leave it as it is for now and push a new version of boot-figreload

juhoteperi22:01:48

^ http://boot-clj.github.io notifications are probably unnecessary

alandipert22:01:35

hm, looks like we have an organization webhook

alandipert22:01:08

do we like the notifications for the other boot/* projects?

alandipert22:01:31

i'm kind of for no notifications

juhoteperi22:01:36

yeah, this channel is so active that it might be best to just turn of notications completely

mobileink22:01:09

hey bootsters! i'll bet a lot of you think of boot as a build system. not so! it's JCL (Job Control Language), done right! https://clojurians.slack.com/archives/google-cloud/p1485816735000754

geoffs23:01:37

Is there actually support for passing non-keyword arguments to a task? I thought I saw something with like boot my-task [ sequential args ] but I can't seem to find any info on it in the wiki...

micha23:01:42

@geoffs you can do boot [ mytask --opt1 optarg1 arg1 arg2 ]

geoffs23:01:08

ohhh, with the whole task name inside the [] thanks @micha