Fork me on GitHub
#boot
<
2016-02-03
>
jethroksy03:02:07

Gratz @seancorfield your blog post appeared on the news

seancorfield03:02:27

Good news travels fast! simple_smile

jethroksy03:02:04

Also to throw in ideas for possible explorations of boot new

jethroksy03:02:19

I really like Docker's way of building up templates

jethroksy03:02:01

I can imagine that it'd be significantly easier given that we would only be working on a local filesystem

jethroksy03:02:15

I'd create a setup.boot

jethroksy03:02:47

And then inside I'd have FROM giturl and I could do some other setup inside like DEPS ...

jethroksy03:02:25

Then I'd run boot setup and there's my folder all ready to go

seancorfield03:02:58

You mean using a Git repo as a template in some form?

seancorfield03:02:11

(rather than a deployed artifact from Clojars / Central)

jethroksy03:02:41

Deps would be pulled in since it generates the build.boot with the dependencies vector

jethroksy03:02:47

Of course this is all somewhat hypothetical

seancorfield03:02:10

And how would it be different from git clone followed by ... something? What? Not sure how it would work.

jethroksy03:02:04

It is somewhat like git clone followed by something

jethroksy03:02:28

In a similar way to how boot can build up tasks

jethroksy03:02:51

It can build up the project by composing other hypothetical tasks

jethroksy03:02:08

Like tasks to add more deps to other peoples setup.boot

jethroksy03:02:54

Like perhaps you have a setup.boot that I really like to use, but you don't use cider and I'd really like that

jethroksy03:02:59

I would do (comp (from "seancorfield/boot template") (add " foo/cider"))

jethroksy03:02:04

Something like that

seancorfield03:02:01

Given that you can add a dependency with (merge-env! :dependencies '[[foo/cider "RELEASE"]]) I'm not sure why you'd need a task for it...

jethroksy03:02:45

Because 'foo/cider' doesn't just add deps

jethroksy03:02:07

It generates the code to plug middleware in

seancorfield03:02:14

Oh, so foo/cider would be another template you'd want to generate in?

jethroksy03:02:25

Template composing

seancorfield03:02:35

Sounds like the planned "generator" aspect of Boot new is exactly what you want...

seancorfield03:02:49

Release 0.4.0 will have a first cut of that.

jethroksy03:02:41

I guess that, and a declarative Bootfile

seancorfield03:02:54

You can already add in complete template, just by running boot new, with -f / --force if you want it to overlay an existing directory tree.

seancorfield03:02:09

And the -g / -generate option will be like a mini-template to add smaller pieces than a "project", including being able to add stuff to existing files.

jethroksy03:02:34

Hopefully it all gets merged into core

seancorfield03:02:32

Micha mentioned that possibility the other day. I want it to "bake" as a standalone project for a while, and then we can see how best to fit it into core without adding too much machinery.

seancorfield04:02:10

For example, right now it always depends on Stencil and we might not want to bake that into core (even just for the new task).

jethroksy04:02:21

I can imagine a spike in users of boot when creating boot templates become a lot easier

seancorfield04:02:34

boot -d seancorfield/boot-new new -t template -n mytemplate simple_smile

seancorfield04:02:22

That'll get you started... I need to expand it tho'... I didn't realize how minimal the Leiningen template template was until I'd integrated it into boot-new...

seancorfield04:02:44

In fact I'll go create a ticket about that so I don't forget

seancorfield04:02:27

OK, issue #10. Make the generated Boot template rich enough to be able to use it to generate a minimal Boot project...

jethroksy07:02:47

Thanks for all the hard work @seancorfield

jethroksy07:02:23

My work involved me travelling all around my island, and its hard to find time to sit down and do all these stuff 😞

levitanong08:02:56

I’ve been waiting for a long time for a template generator for boot. Thanks for your effort, @seancorfield!

martinklepsch10:02:48

@seancorfield: great post once again. noticed the Framework One link is dead but at the same time not sure if it was supposed to work? 😄

donmullen12:02:05

@micha Where is the hoplon template? You mentioned that dependencies are auto-generated to latest - want to take a look.

donmullen12:02:38

Ha! Should have thought to look there. Thanks @alandipert

dominicm14:02:53

Looking for a hand with pods, dependencies, and tasks. Me and @malcolmsparks have been trying to get Clojure/Clojurescript dependencies isolated from one another, so that they can't leak into one another's dependencies unexpectedly, and also a little isolation from the boot task libraries is nice, due to potentially outdated deps. https://github.com/juxt/edge/blob/master/build.boot#L4

dominicm14:02:23

The server task, currently calls the nrepl-server function directly, and creates a pod for that situation. I imagine this is the best way to handle that.

martinklepsch14:02:09

@dominicm: can you share the motivation for splitting those deps?

dominicm14:02:29

https://github.com/juxt/edge/blob/master/build.boot#L39 The real trouble is in the frontend, where to override the cljs task's pod, I'm having to use intern and alter-var-root to override the pod environment.

micha14:02:11

@dominicm: also, incidentally, boot tasks don't need to be isolated from anything becuase they don't have transitive dependencies

micha14:02:35

they load their own dependencies into pods of their own

micha14:02:43

so they perform the isolation for you

dominicm14:02:45

@martinklepsch: Isolation from one another mostly. Clojurescript libraries otherwise are pulled into Clojure, etc.

martinklepsch14:02:16

@dominicm: if you want to avoid having these libs on the classpath when running things in prod maven scopes might be just enough?

dominicm14:02:30

@micha should have been more specific, top-level dependencies, e.g. for the clojurescript task, you need a global piggieback, but that depends on an extremely old clojurescript, that shouldn't pollute other things.

micha14:02:54

@dominicm: ah yeah this is a sticky problem simple_smile

micha14:02:13

i recommend global :exclusions usually in these cases

dominicm14:02:22

@martinklepsch: The point is more to have them buildable from the same command, without interacting. boot frontend server

micha14:02:36

the cljs-repl task for example, will add its own piggyback dependency if none is already on the classpath

micha14:02:54

so to prevent another dep from pulling it in transitively you can use global exclusions

martinklepsch14:02:28

@dominicm: wondering wrt piggieback — should that depend on cljs with :scope "provided"?

micha14:02:30

so the real problem with things like the clojurescript dependency, or piggyback, is that lots of libraries depend on random old versions of it

micha14:02:56

so if you don't provide the explicit dependency it's up to luck which version is on the classpath

dominicm14:02:04

@micha: cljs-repl does a really good job.

dominicm14:02:14

@martinklepsch: I believe so, yup.

micha14:02:16

but an alternative is to globally exclude things like cljs and piggieback

micha14:02:28

and let the tasks load their own versions into their pods

micha14:02:48

those tasks have the latest compatible version hardcoded into them

micha14:02:02

and i believe they check the classpath and figure out how to do

dominicm14:02:15

@martinklepsch: But I believe that leiningen tells you to use a provided profile instead of messing with scope. No idea if this affects boot's handling at all (as there is some crossover)

dominicm14:02:22

@micha: Yeah. That definitely helps with the top-level dependencies. It's admittedly not the primary concern, as well-written tasks do a good job. But it's also nice not to think about it.

micha14:02:43

these are issues with library versioning and stability

micha14:02:16

if we were more disciplined about releasing semantic versions we would have an easier time

micha14:02:34

but when there are 0.x releases that are like 5 years old and everything depends on them

micha14:02:43

you put yourself in dependency hell

micha14:02:05

like core libraries need to be versioned sanely

dominicm14:02:08

The real killer feature is, for example, you could depend on different versions of core.async on frontend/backend, or not accidentally pull in cemerick/url into our server application, when we only want to use it on the frontend.

micha14:02:55

i'm no longer such a big fan of using scopes for things like piggieback's cljs dependency

micha14:02:04

because it hides issues as much as it helps

micha14:02:26

i think the only real solution is to be disciplined about versioning

micha14:02:41

so tools can help you figure it out

micha14:02:56

but that's not idiomatic simple_smile

dominicm14:02:00

@martinklepsch: Nobody has reported that before? 😮

micha14:02:41

like piggieback doesdepend on cljs

micha14:02:57

so "provided" isn't really going to help i don't think

micha14:02:14

because it then hides the cljs dependency from tools that track conflicts

dominicm14:02:42

@micha: But when it's run, it expects the environment to provide that dependency, and it's version shouldn't be pulled in.

micha14:02:57

i don't think that's correct

micha14:02:13

it was built and tested against a certain version of cljs

micha14:02:28

there is no reason to think that it will work with other random versions of cljs

micha14:02:48

the way you'd figure it out is to look at boot show --pedantic for example

micha14:02:04

then you could see if the thing isn't working that it depends on some other version of cljs

micha14:02:11

and you can start to debug the problem from there

micha14:02:47

but now if you have 10 dependencies in your project that all depend on different incompatible versions of something, now you're in a mess

micha14:02:57

and adding scope "provided" won't help there

micha14:02:03

it will just obscure the problem

micha14:02:11

because you won't even know that there were transitive dep conflicts

micha14:02:23

that's the symptom

micha14:02:32

and we can treat the symptom in various ways, like pods etc

micha14:02:50

but the disease is library stability and versioning practices, imho

micha14:02:16

you can achieve the same effect as if piggieback had used :scope provided by doing this:

micha14:02:31

(set-env! :exclusions '[org.clojure/clojurescript])

malcolmsparks14:02:19

I really like pods, they are very useful for writing tasks, and it was very good that nrepl can run in a separate pod - the problem was were struggling with yesterday is isolating the dependencies we needed for the boot script, and the dependencies we wanted in our cljs build. Really we want to build the back-end and front-end of our project using the same build.boot file, where each can have a separate set of dependencies (and obviously a third set of dependencies for the boot script itself)

malcolmsparks14:02:05

(my current strategy of using lein for the backend and boot for the cljs front end is causing people in my training courses to get very confused 😉

micha14:02:16

you can modify the dependencies that the tasks see, and thus control which deps are loaded in the task pods

malcolmsparks14:02:20

it goes without saying that I want to migrate everything to boot simple_smile

micha14:02:44

generally tasks just add things to the existing build.boot dependencies from get-env

micha14:02:54

that's how they build the env that the pod will have

micha14:02:33

so it's possible to write a macro for instance that wraps the tasks setting different :dependencies

micha14:02:39

so those tasks see different deps

malcolmsparks14:02:48

tasks can specify their own dependencies, by modifying (get-env) - I understand that - but we want to change the dependencies of an /existing/ task (boot-cljs) - not sure how to do that...

micha14:02:57

i believe @martinklepsch has such a thing somewhere

micha14:02:08

roughly like this:

martinklepsch14:02:00

@micha: don't think so — reminds me if your with-env though

malcolmsparks14:02:22

yeah, it's the with-env thing we're looking for definitely

micha14:02:31

(deftask build-it
  [ ... ]
  (comp
    (watch)
    (foo)
    (with-dependencies
      '[[foo/bar "1.2.3"] ...]
      (cljs :optimizations :advanced))
    (with-dependencies
      '[[baz/baf '4.5.6"]]
      (some-other-task)))

micha14:02:11

i've used this to get around jetty dependency issues when i didn't want to spend the time futzing around with exclusions

malcolmsparks14:02:18

boot.repl takes a pod argument, but no many other tasks do - really you want to be able to tell a task which pod to run in, or alternatively, use as it's basis - but with-env sounds a similar idea

micha14:02:38

tasks themselves need to run in the core pod

micha14:02:45

because that's where all the state is

micha14:02:55

the classpath for example isn't thread safe

micha14:02:03

but the work is done in pods

micha14:02:19

those pods can be influenced when they're constructed

micha14:02:24

which is before the pipeline is run

micha14:02:38

when the individual task middleware are created

micha14:02:49

that's the with-env idea

malcolmsparks14:02:01

oh ok. This with-dependencies would do the job for us actually - do you have a reference for it?

[email protected] boot]$ git grep with-dependencies
Makefile:baseuber     = boot/base/target/base-$(version)-jar-with-dependencies.jar
Makefile:       (cd boot/base && mvn -q assembly:assembly -DdescriptorId=jar-with-dependencies)
[[email protected] boot]$ 

malcolmsparks14:02:25

with-env would be more powerful

micha14:02:33

i have it somewhere

martinklepsch14:02:34

tried finding the gist but couldn't

micha14:02:44

it's in the boot-builds-boot branch, no?

malcolmsparks14:02:45

it's somewhere on the internet, we just can't find it!

martinklepsch14:02:14

don't think so, we switched to running multiple pipelines

martinklepsch14:02:49

every time again enjoying the look of that macro. just looks like keyboard smashing...

micha14:02:28

(defmacro with-env
  [deps task]
  `(let [#orig (get-env :dependencies)]
     (set-env! :dependencies ~deps)
     (let [#ret ~task]
       (set-env! :dependencies #orig)
       #ret)))

alandipert14:02:18

it's rhomboid so you know it's good

micha14:02:25

haha totes

alandipert14:02:32

yup, rhomboid 👌

malcolmsparks14:02:54

it's a level of macro mastery that is truly impressive

alandipert14:02:43

we can't praise micha too much or else he might retire and leave us with all these macros

micha14:02:51

i wonder if boot should have a dynamic var that when bound would cause boot to not actually load deps when you set-env!

micha14:02:03

that way you could "fake" dependencies for the task pods

micha14:02:44

(binding [*resolve-dependencies* false]
  (set-env! :dependencies ...))

micha14:02:01

or perhaps better:

micha14:02:37

(with-unresolved-dependencies
  [[foo/bar "1.2.3"] [baz/baf "4.5.6"]]
  ...

micha14:02:59

that would do the setting and restoring without actually adding new jars to the classpath

alandipert14:02:05

-1 exposing dynvars as api, +1 macro

micha14:02:07

so you can trick the tasks

micha14:02:15

yeah agree

alandipert14:02:25

but yeah that would be sweet

micha14:02:49

we can make a patch i think for now, @malcolmsparks if that would help you

micha14:02:15

a snippet that you can put in your build.boot that patches the aether stuff and adds this macro

alandipert14:02:26

i wonder if deftask isn't the place to hang these things

alandipert14:02:40

like in the precondition hole

micha14:02:03

it's more for when you want to modify how an existing task works

micha14:02:13

so a macro wrapper seems ideal

micha14:02:46

it basically turns the env into a dynamic var

micha14:02:59

that macro binds to a different value for the extent of the body

alandipert14:02:59

so maybe the wrapper should put meta on the fileset fn? the weird thing i see with it is added confusion b/c dynamic extent

alandipert14:02:13

like you couldn't wrap a task constructor with this and then return what the constructor did

micha14:02:32

that's the idea, no?

alandipert14:02:45

i guess it works as long as the resolution is happening in the task constructor

micha14:02:10

(comp
  (with-env ...
    (foo-task :opt val))
  (bar-task :opt val))

micha14:02:16

because the bindings are only known by the code that instantiates the task, not by the task itself

micha14:02:31

basically like an extra parameter to tasks, the env

micha14:02:47

so you can override the global env when constructing that one task

alandipert14:02:13

(defn cool []
  (with-env ...
    (foo-task :opt val)))

(comp
  (cool)
  (bar-task :opt val))

alandipert14:02:49

would that work?

alandipert14:02:44

it seems that the gotcha is the deps stuff needs to happen in the foo-task constructor

micha14:02:54

i think that would work

alandipert14:02:25

not a gotcah i guess, that is the recommended place, but so far we've never depended on it anywhere

micha14:02:30

yeah but it's binding when (cool) is called

micha14:02:35

which makes sense, no?

micha14:02:59

and in the core pod all the things are running in the same thread

micha14:02:07

so there is no need for bound-fn business

alandipert14:02:12

ok i see, yes they are equivalent

alandipert14:02:20

ok i'm almost out of objections

alandipert14:02:41

binding-env maybe is better than with-env since it pushes and pops bindings in a way

micha15:02:45

ok one more question @alandipert

micha15:02:10

(binding-env
  {:dependencies '[[foo/bar "1.2.3"]]}
  (a-task))

alandipert15:02:15

ok i had a thought about what the Right Thing is

alandipert15:02:28

like taking a step back, maybe the underlying thing that sucks is that filesets can't go between pods

micha15:02:29

(binding-env
  :dependencies '[[foo/bar "1.2.3"]]
  (a-task))

alandipert15:02:49

if they could, there would be no reason to pollute your global env before you started your task pipeline

micha15:02:06

how would that help?

micha15:02:30

currently the model is simple, the tasks create pods by building on the env of the main pod

micha15:02:46

so dynamic binding seems straightforward

alandipert15:02:50

the reason to dissociate deps from the env before constructing foo-task is because there are deps in the calling environment that aren't compatible with the task, right?

micha15:02:02

no, the other way, i think

micha15:02:11

or i guess both

micha15:02:26

like you want deps in the pod that aren't loaded into the main pod

micha15:02:40

because the main pod will create other pods that will have incompatible deps

micha15:02:02

like if you want a different version of core.async for task A than for task B

micha15:02:24

both of those tasks will create their pods using the version of core.async they see in the main pod's env

micha15:02:06

(comp
  (binding-env
    {:depdencies '[[org.clojure/core.async "1.2.3"]]}
    (A ...))
  (binding-env
    {:dependencies '[[org.clojure/core.async "4.5.6"]]}
    (B ...)))

alandipert15:02:38

an equivalent way to do it would be to run the task function in a pod

alandipert15:02:49

it seems like this binding-env thing is a poor man's pod

alandipert15:02:55

necessary only because filesets can't go between pods

alandipert15:02:38

that even looks like you're making a pod

alandipert15:02:42

except you're not, you're doing a workaround thing

micha15:02:01

but tasks need access to boot.core

micha15:02:13

which would be very difficult to provide in another thread

micha15:02:51

i guess if boot.core had some kernel implemented in java perhaps

micha15:02:06

that could be used to clone it in anpother pod

alandipert15:02:36

or maybe in a pod the boot.core you see is a bridge ns that de/serializes

micha15:02:40

that would work, if you add some kind of locking semantic when you add it to the pipeline

micha15:02:35

if you do that though you have the shenanigans in a different place

micha15:02:51

instead of dynamic extent coconut you have locking and synchronization coconut

alandipert15:02:04

the only problematic thing in boot.core is set-env! right?

micha15:02:05

and the whole proxying coconut lol

alandipert15:02:16

like the singleton environment is what boot.core represents

micha15:02:32

more or less yeah, i think so

micha15:02:43

not 100% sure

micha15:02:56

there is a lot of stuff going on in there

alandipert15:02:17

also the fileset system

micha15:02:19

there are also atoms though

alandipert15:02:21

that's the other resource

micha15:02:29

which can't really be transmitted to other pods

micha15:02:48

you could make linked blocking queues to do it

micha15:02:04

but you'd need to use add-watch, which isn't the same concurrency semantic

alandipert15:02:14

in any case this feels like a 3.0 thing

alandipert15:02:39

i like the idea of cutting down the places with essential global state to a few specific places

micha15:02:58

implementing the mutable state in java seems like it could simplify things

micha15:02:12

and boot.core is just building clojure wrapper for that

micha15:02:32

boot.core is a proxy for the java madness

micha15:02:44

which can be safely shared across pods

micha15:02:55

because the interface would be via java.util.concurrent queues etc

alandipert15:02:04

yeah and when you call functions in it you're enqueing things for execution in the lower level java singleton enviro

micha15:02:11

exactly yeah

micha15:02:38

we could probably do this without making breaking changes

micha15:02:19

i guess things like :dependencies would be per-pod

alandipert15:02:25

maybe put the binding-env thing in for now but mark it deprecated lol

micha15:02:27

or this would not solve the current problem

micha15:02:36

that makes things more complicated

alandipert15:02:54

yeah i was thinking about how the Ideal Bootfile

alandipert15:02:02

only uses maven to pull in names of tasks

alandipert15:02:16

but lots of times that's not what you want

alandipert15:02:22

like a big project, it is what you want

alandipert15:02:34

everything you're doing you factor into a task outside your build.boot

alandipert15:02:53

but like in small and medium apps maybe you have some tasks inline, and they'll need to make uses of deps in that environment

micha15:02:20

those cases don't have the same isolation requirements, becaus they're not huge

alandipert15:02:29

maybe a new kind of build.boot?

alandipert15:02:34

like system.boot or something

micha15:02:41

i think the binding macro will be a 99% solution really

micha15:02:11

it doesn't really add any new abstractions, which is good

micha15:02:52

and i think it's safe to fake the dependencies at least, becuase task libraries don't have transitive deps

micha15:02:08

so like the task itself won't use core.async in the task namespace, it'll use core.async in a pod

micha15:02:25

which will be constructed based on the :dependencies it sees when it's constructed

micha15:02:10

so :dependencies, :directories are ok to fake i think

micha15:02:31

i guess all the things really

alandipert15:02:54

probably also too complicated but another seam is boot-in-boot

micha15:02:18

yeah that's the gold standard, complete isolation

micha15:02:30

also can run in parallel

alandipert15:02:41

that would require a way to stitch boots together

micha15:02:45

which seems like what @malcolmsparks could use

alandipert15:02:49

seems easy-ish

micha15:02:03

yeah in my demo i use a semaphore to make them run sequentially

micha15:02:21

but you can use countdown latches for concurrent execution

dominicm15:02:32

Warning: version conflict detected: org.clojure/clojurescript version changes from 1.7.170 to 0.0-3165
How do version changes work with regards to set-env!, or more specifically, with-env

dominicm16:02:01

I'm seeing quite a few version conflicts really, for the frontend task.

dominicm16:02:20

ah, I think I see what is going on.

dominicm16:02:34

When the set-env! returns the previous state, the clojurescript & such is being restored.

dominicm16:02:32

I was seeing double.

micha16:02:08

yeah we need to implement the dynamic var that will disable actual loading of the "fake" dependencies in the core pod

micha16:02:30

we can do that i think via intern and alter-var-root if you like

dominicm16:02:07

Ah, so there are limitations to the with-env macro. I thought you were discussing an edge case there. @micha If it's a possible solution, let's give it a try. No harm right?

micha16:02:16

yep one sec

dominicm16:02:15

> Modifying or replacing your boot's software via macros may void your device's warranty, lead to data loss, hair loss, financial loss, privacy loss, security breaches, or other damage, and therefore must be done entirely at your own risk. No one affiliated with the CyanogenMod boot project is responsible for your actions. Good luck.

dominicm16:02:36

> CyanogenMod Boot members or anyone else on this website is not responsible for bricked devices, dead SD cards, thermonuclear war, or you getting fired because the alarm app failed. I knew there was one about nuclear war.

micha16:02:17

@dominicm: ^^

micha16:02:32

you can put that at the top of your build.boot

micha16:02:37

that should do the thing

micha16:02:01

(comp
  (with-env
    {:dependencies '[[foo/bar "1.2.3"]]}
    (some-task :option some-option))
  ...

micha16:02:02

it's a little bit of a hack because i had to use an atom instead of a dynamic var

dominicm16:02:14

@micha: Giving it a spin now.

micha16:02:16

i don't know how to create a dynamic var at runtime in a namespace

micha16:02:49

but the atom works the same so it's ok

sooheon16:02:03

I was under the impression that simply adding a cljsjs lib to :dependencies, then requiring it in the right namespace took care of declaring externs for you (as in this example https://github.com/cljsjs/packages/tree/master/nvd3). Does boot do things any differently, that I should still get mangled fn names with advanced compilation?

dominicm16:02:25

I had to prefix the set-env! and get-env with boot.core btw.

micha16:02:28

no, externs should be automatic

micha16:02:53

@dominicm: oh, yeah defining macros in build.boot is weird

micha16:02:15

i was working witha file and testing with load-file in the repl

micha16:02:27

i didn't actually test pasted into a build.boot

dominicm16:02:49

the with-env may need to handle some evaluation for things too, as my environment for cljs is calculated (basically just filters a few deps from the main ones, as boot-cljs has to be loaded within it's pod to work.)

micha16:02:22

anything in the expr should be able to use get-env to see the "fake" dependencies

micha16:02:20

(comp
  (with-env
    {:dependencies (mangle-deps (get-env :dependencies))}
    (cljs :optimizations :advanced))
  ...

dominicm16:02:09

Does mangle-deps work if it's let-bound above the comp?

dominicm16:02:29

Hmm, isn't for me. That's what I'm trying to get at :s

micha16:02:30

it's just a function that returns the deps vectors

micha16:02:40

not following

dominicm16:02:08

(with-env
     cljs-env
     (cljs :ids #{"edge"} :optimizations :none))
=> java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol

dominicm16:02:36

My macro-fu isn't great.

micha16:02:39

what is cljs-env

micha16:02:10

i see, one sec

dominicm16:02:13

(let [cljs-env {:dependencies (-> (boot.core/get-env :dependencies) remove-unneeded-deps (concat @@(resolve 'adzerk.boot-cljs/deps)) (concat cljs-deps) vec) :source-paths #{"src" "dev-cljs" "resources"}}])])

micha16:02:23

yeah one sec

micha16:02:31

i was being too clever with that macro, as always

dominicm16:02:22

haha, macros are always trying to be too clever 😛

dominicm16:02:47

I've never been able to fully internalize the full macro syntax.

micha16:02:52

this should work now, hopefully

micha16:02:16

oops forgot to delete a line

micha16:02:19

updated for real now

micha16:02:59

the set-env! below the apply set-env! needs to be removed

micha16:02:50

(intern
  (the-ns 'boot.core)
  'resolve-dependencies? (atom true))

(alter-var-root
  #'boot.core/add-dependencies!
  (fn [orig]
    (fn [old new env]
      (if @boot.core/resolve-dependencies? (orig old new env) new))))

(defmacro with-env
  [env-map expr]
  `(let [orig-env# (get-env)
         new-env#  ~env-map]
     (reset! boot.core/resolve-dependencies? false)
     (apply set-env! (mapcat identity new-env#))
     (let [result# ~expr]
       (apply set-env! (mapcat identity orig-env#))
       (reset! boot.core/resolve-dependencies? true)
       result#)))

dominicm16:02:46

@micha: After removing the second apply, => java.lang.RuntimeException: Unable to resolve symbol: cljs-env in this context

micha16:02:10

is it actually defined in your build.boot?

micha16:02:09

some macro tinkering is in order, but that's the general idea of it

dominicm16:02:09

ugh, I just checked my indentation...

(let [])
(comp)

dominicm16:02:13

Running again

micha16:02:30

i mean the cljs-env var needs to be defined somewhere

micha16:02:50

yeah or lexical binding for it

dominicm16:02:28

@micha: Yeah, I made a stupid mistake. The let binding is pretty unwieldly at this point.

micha16:02:40

haha i do that all the time also

dominicm16:02:27

#C0F2A0MJN usually helps, but when the let is so big, my eyes can't line things up.

micha16:02:10

the suspense is building

micha16:02:13

does it work?

dominicm16:02:46

@micha ish.. for some reason om isn't being pulled in (possibly other cljs deps too)

micha16:02:14

they will only be pulled into the pods that the wrapped tasks create

dominicm16:02:05

{:dependencies [[adzerk/boot-cljs 1.7.48-5 :scope test] [adzerk/boot-reload 0.4.0 :scope test] [weasel 0.7.0 :scope test] [ns-tracker 0.3.0] [org.omcljs/om 1.0.0-alpha28] [org.clojure/core.async 0.2.374] [org.clojure/clojurescript 1.7.170]], :source-paths #{src dev-cljs resources}}
I see.. hmm.. I wonder if boot-cljs isn't compiling in a pod..

micha16:02:11

oh, i think i know why

dominicm16:02:20

yeah? Okay!

micha16:02:28

hm nm, it was doing the right thing already

micha16:02:52

i thought maybe boot.pod/env wasn't being set

micha16:02:55

but it was

dominicm16:02:09

in boot-cljs?

micha16:02:16

i mean the macro

micha16:02:52

the boot-cljs task should be just adding its own deps to whatever it gets from (get-env) or boot.pod/env

micha16:02:59

so the macro should work

dominicm16:02:07

Yeah, it is.

micha16:02:22

one thing you can do is run your pipeline as an incremental build

micha16:02:32

and start a repl server in the cljs pod

micha16:02:38

then you can look around in there maybe

micha16:02:42

see what's on the classpath

micha16:02:50

or even easier actually

micha16:02:53

you can do like

micha16:02:21

boot my-task-with-macro show --pod adzerk.boot-cljs --deps

micha16:02:34

something like that

micha16:02:59

boot task-with-macro show --list-pods will show the names if what i wrote above isn't correct

micha16:02:13

the pods are by default named after the namespace of the function that created them

micha16:02:36

so you can see which deps are loaded in the pod

dominicm16:02:57

https://gist.github.com/SevereOverfl0w/13e93b7fcadbac8ba741 I'm not doing anything obviously wrong in frontend am I? Just running the show thing now

micha16:02:56

looks good to me

micha16:02:13

one thing is that :source-paths doesn't mean anything to pods really

micha16:02:16

so you want to do like

dominicm16:02:28

:directories?

micha16:02:41

{:directories (conj (get-env :directories) "sass")}

dominicm17:02:03

yeah, I bumped into that one before, I wasn't sure if it would work now though, but good to know it's the same here.

micha17:02:26

yeah you're basically faking the env for pods

micha17:02:30

so the pod stuff applies

dominicm17:02:47

With the show, how do I do that given that the frontend is crashing? Take cljs out of the with-env?

dominicm17:02:24

For now I'm just gonna move the set-env! deps up, and see if that helps

dominicm17:02:53

I'm definitely lost on what to try next.

taylor.sando17:02:15

I have a boot project and I would like to do a checkout dependency on om (a leiningen) project. What's the easiest way of doing it?

martinklepsch17:02:47

@taylor.sando: build the project with boot simple_smile

martinklepsch17:02:27

@taylor.sando: stupid answer but I think it is actually the easiest/quickest way

dominicm17:02:29

@micha did the repl, checked the classpath, old versions of clojurescript are being used, for sure.

dominicm17:02:40

oh, but that might be normal, with analyzer...

taylor.sando17:02:52

You mean build om with boot?

martinklepsch17:02:13

@taylor.sando: yeah, and then use the checkout task in your own project boot checkout -h

dominicm17:02:06

@micha yeah, so if I include clojurescript, that's good. But for some reason om isn't being pulled into the classpath of the pod.

micha17:02:23

@dominicm: but other deps are?

dominicm17:02:54

I don't think so @micha , I'll confirm once I'm sat on the train

dominicm17:02:37

Is it possible we've accidentally prevented additional dependencies from being pulled in?

micha17:02:23

i tested that it pulls des into the pods

dominicm17:02:01

@micha my repl task isn't pulling in deps either

dominicm17:02:55

But can find things via directories..

micha17:02:21

repl task?

dominicm17:02:19

Repl task, which is wrapped. In the gist it's called server (in edge too)

dominicm17:02:48

Wraps it with some dependencies so I can start the server component

dominicm17:02:55

Bidi is one of them

micha17:02:09

hm i'll see what's up this evening

micha17:02:34

it might have something to do with weirdness of putting it in build.boot, the macro

micha17:02:50

i was using a file, that tmp.clj file in my gist

micha17:02:05

and loading it in the repl via (load-file "tmp.clj")

dominicm17:02:17

Okay, thanks.

dominicm17:02:25

This will be really cool if we figure it out

dominicm17:02:39

I'll see if load file works in a build

micha17:02:39

boot.user=> (with-env
       #_=> {:dependencies (conj (get-env :dependencies) '[org.clojure/clojure "1.6.0"])}
       #_=> (let [p (boot.pod/make-pod (get-env))]
       #_=>   (boot.pod/with-eval-in p (clojure-version))))
"1.6.0"

dominicm17:02:54

@micha could you try with a different dep? I just tried using bidi, no cigar

micha17:02:09

ok one sec

micha17:02:15

what's the dep vector?

micha17:02:31

boot.user=> (load-file "tmp.clj")
#'boot.user/with-env
boot.user=> (with-env
       #_=> {:dependencies (conj (get-env :dependencies) '[org.clojure/clojure "1.6.0"])}
       #_=> (let [p (boot.pod/make-pod (get-env))]
       #_=>   (boot.pod/with-eval-in p (clojure-version))))
Retrieving clojure-1.6.0.jar from 
"1.6.0"

micha17:02:39

i deleted clojure from my .m2

micha17:02:43

and it fetched it

dominicm17:02:11

[bidi "1.24.0"]

dominicm17:02:13

Yeah, clojure works for me too

micha18:02:20

boot.user=> (with-env
       #_=> {:dependencies (conj (get-env :dependencies) '[bidi "1.24.0"])}
       #_=> (let [p (boot.pod/make-pod (get-env))]
       #_=>   (boot.pod/with-eval-in p (clojure-version))))
Retrieving schema-1.0.3.jar from 
Retrieving bidi-1.24.0.jar from 
"1.7.0"

micha18:02:59

it seems to be dong it

micha18:02:59

ah i see the problem

dominicm18:02:12

Yeah? Awesome

micha18:02:25

it's the boot-cljs task

micha18:02:33

it creates the pod during the pipeline

micha18:02:15

we can fix that though

micha18:02:33

it just needs to configure the deps before the pipeline starts

dominicm18:02:37

Oh.. Oh great!!

micha18:02:40

i.e. outside of with-pre-wrap

micha18:02:50

it can still create the pod later

micha18:02:12

it just needs to decide which deps to use in the outermost let binding

dominicm18:02:57

Ah yes, I understand

dominicm18:02:44

That's the function I was intern overriding previously to set dependencies

micha18:02:14

ah sweet, so you've got a fix that you can work with then

dominicm18:02:24

You think just overriding that is best for cljs for now? should I look at modifying the task in a fork?

micha18:02:14

the best thing is probably to save the (get-env) in the outermost let binding of the cljs task

micha18:02:27

and stash it somewhere i guess

micha18:02:34

so that the new-pod! function can use it

dominicm18:02:42

Yeah, if I have the source locally, I'll try and hook that up

micha18:02:22

it shouldn't break anything to make this change, as i don't think anything depends on being able to mutate the env once the pipeline has started

micha18:02:29

that would be pretty crazy

dominicm18:02:16

I wonder if it was done for the possibility of dependency hot loading... Even that seems a bit of a stretch though

micha18:02:30

yeah the pod is only created once

micha18:02:16

the reason why it's making the pod during the pipeline is because it doesn't know how many pods it will need until it sees the fileset

micha18:02:48

i don't think we did it that way for resolving dependencies in a special way

taylor.sando18:02:31

@martinklepsch: The dev task I'm using. Should I stick a checkout in there? Such as (checkout [['org.omcljs/om "1.0.0-alpha31-SNAPSHOT"]]), after the watch task?

dominicm18:02:26

@micha ah, that's quite interesting. I wasn't sure how much the oss stuff would be touched by everyone. How many of you are there at adzerk?

micha18:02:02

6 devs currently

micha18:02:45

@juhoteperi is the boss of the boot-cljs project

micha18:02:11

so you could submit a PR if you figure out a good fix

dominicm18:02:13

I took a look at the product, I thought it was a really neat system. Yeah, I'd noticed. Had no idea if he was associated with boot officially or not though. Hopefully it will be PR-able. I think Malcolm wants me to write up what we've managed to pull off, so I'd definitely prefer to have it in the upstream repo

micha18:02:02

yeah sweet, i think he'd be okay with that change

richiardiandrea19:02:34

Hello guys, how can I return a value from a build.boot ? Say, as per my PR, I am testing and the tests are failing?

micha19:02:14

(System/exit 1)

richiardiandrea19:02:29

Lol perfect, I knew it was easy 😄

micha19:02:38

haha yeah we're just computing!

micha19:02:59

that's the default if an unhandled exception is thrown by the way

micha19:02:08

so you can just throw an exception probably

micha19:02:24

that will work better, i think, because it will even work with boot-in-boot

micha19:02:39

runBoot() will return the "exit status"

micha19:02:51

so runBoot() normally returns 0 on success

micha19:02:03

or 1 if you threw an exception that wasn't caught by anything

richiardiandrea19:02:15

ok good, it still feels cleaner to collect and exit with system.exit, but I will see, I am running boot in boot and I could even just throw

richiardiandrea19:02:34

but no, I have the info to set System.exit

micha19:02:41

yeah calling System/exit in a nested boot will terminate everything

micha19:02:45

which you don't want

micha19:02:09

so yeah just throw an exception

richiardiandrea19:02:24

nice, can use getMessage and set my own code

richiardiandrea19:02:36

you have thought out everything already 😄

micha19:02:18

alan's masterpiece of tricking the JVM into doing something

richiardiandrea19:02:20

I have to say that in theory the parallel testing stuff could be generalized to parallel boot tasks

richiardiandrea19:02:23

but I will maybe leave this to someone else, gotta switch to some other stuff soon

richiardiandrea19:02:39

the code is there already, just need to rename stuff 😄

richiardiandrea19:02:11

as you were saying earlier I am using CountDownLatch for syncing

richiardiandrea19:02:47

(btw please review the code because concurrency is always tricky, especially the sync-map part)

martinklepsch19:02:47

was the conclusion here now that scope provided for piggieback is a bad idea? https://github.com/cemerick/piggieback/issues/70#issuecomment-179407012

micha19:02:42

yeah i think the problem can't really be solved with something as simple as that

micha19:02:11

because like it still depends on that version, so if you use a different version it could still not work

micha19:02:25

the scope just masks the problem by not showing a depenedncy conflict

micha19:02:54

so in the end i think we can't really fix the cause that way, only one of the symptoms

micha19:02:37

i think :exclusions is a better fix, in the consumer's build.boot

micha19:02:56

like globally exclude org.clojure/clojurescript

micha19:02:07

then boot-cljs will be able to choose the version it wants