This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-02-03
Channels
- # aatree (5)
- # admin-announcements (52)
- # announcements (1)
- # aws (2)
- # beginners (55)
- # boot (494)
- # braid-chat (17)
- # cider (2)
- # cljsjs (4)
- # cljsrn (8)
- # clojure (157)
- # clojure-austin (6)
- # clojure-czech (7)
- # clojure-denmark (1)
- # clojure-dev (102)
- # clojure-ireland (6)
- # clojure-japan (4)
- # clojure-miami (2)
- # clojure-poland (90)
- # clojure-russia (415)
- # clojurebridge (2)
- # clojurescript (143)
- # core-async (1)
- # datavis (4)
- # datomic (20)
- # devcards (5)
- # dirac (40)
- # emacs (9)
- # events (103)
- # gorilla (1)
- # immutant (122)
- # jobs (3)
- # ldnclj (20)
- # lein-figwheel (1)
- # mount (2)
- # off-topic (22)
- # om (170)
- # onyx (7)
- # overtone (6)
- # parinfer (100)
- # proton (2)
- # re-frame (5)
- # reagent (32)
- # ring-swagger (2)
- # spacemacs (6)
On building Boot new http://seancorfield.github.io/blog/2016/02/02/boot-new/
Gratz @seancorfield your blog post appeared on the news
Good news travels fast!
I can imagine that it'd be significantly easier given that we would only be working on a local filesystem
And then inside I'd have
FROM giturl
and I could do some other setup inside like DEPS ...
You mean using a Git repo as a template in some form?
(rather than a deployed artifact from Clojars / Central)
Deps would be pulled in since it generates the build.boot
with the dependencies vector
And how would it be different from git clone
followed by ... something? What? Not sure how it would work.
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
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...
Oh, so foo/cider
would be another template you'd want to generate in?
Sounds like the planned "generator" aspect of Boot new is exactly what you want...
Release 0.4.0 will have a first cut of that.
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.
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.
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.
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).
I can imagine a spike in users of boot when creating boot templates become a lot easier
boot -d seancorfield/boot-new new -t template -n mytemplate
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
...
In fact I'll go create a ticket about that so I don't forget
OK, issue #10. Make the generated Boot template rich enough to be able to use it to generate a minimal Boot project...
Thanks for all the hard work @seancorfield
My work involved me travelling all around my island, and its hard to find time to sit down and do all these stuff 😞
I’ve been waiting for a long time for a template generator for boot. Thanks for your effort, @seancorfield!
@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? 😄
@micha Where is the hoplon template? You mentioned that dependencies are auto-generated to latest - want to take a look.
Ha! Should have thought to look there. Thanks @alandipert
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
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.
@dominicm: can you share the motivation for splitting those deps?
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.
@dominicm: also, incidentally, boot tasks don't need to be isolated from anything becuase they don't have transitive dependencies
@martinklepsch: Isolation from one another mostly. Clojurescript libraries otherwise are pulled into Clojure, etc.
@dominicm: if you want to avoid having these libs on the classpath when running things in prod maven scopes might be just enough?
@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.
@martinklepsch: The point is more to have them buildable from the same command, without interacting.
boot frontend server
the cljs-repl task for example, will add its own piggyback dependency if none is already on the classpath
so to prevent another dep from pulling it in transitively you can use global exclusions
@dominicm: wondering wrt piggieback — should that depend on cljs with :scope "provided"
?
so the real problem with things like the clojurescript dependency, or piggyback, is that lots of libraries depend on random old versions of it
so if you don't provide the explicit dependency it's up to luck which version is on the classpath
@martinklepsch: I believe so, yup.
@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)
@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.
if we were more disciplined about releasing semantic versions we would have an easier time
but when there are 0.x releases that are like 5 years old and everything depends on them
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.
i'm no longer such a big fan of using scopes for things like piggieback's cljs dependency
@martinklepsch: Nobody has reported that before? 😮
@micha: But when it's run, it expects the environment to provide that dependency, and it's version shouldn't be pulled in.
then you could see if the thing isn't working that it depends on some other version of cljs
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
you can achieve the same effect as if piggieback had used :scope provided by doing this:
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)
(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 😉
you can modify the dependencies that the tasks see, and thus control which deps are loaded in the task pods
it goes without saying that I want to migrate everything to boot
so it's possible to write a macro for instance that wraps the tasks setting different :dependencies
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...
i believe @martinklepsch has such a thing somewhere
@micha: don't think so — reminds me if your with-env
though
yeah, it's the with-env thing we're looking for definitely
(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)))
i've used this to get around jetty dependency issues when i didn't want to spend the time futzing around with exclusions
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
oh ok. This with-dependencies
would do the job for us actually - do you have a reference for it?
malcolm@tulkas 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)
[malcolm@tulkas boot]$
with-env
would be more powerful
tried finding the gist but couldn't
it's somewhere on the internet, we just can't find it!
don't think so, we switched to running multiple pipelines
when you find it ▶️ https://github.com/boot-clj/boot/wiki/Snippets
every time again enjoying the look of that macro. just looks like keyboard smashing...
(defmacro with-env
[deps task]
`(let [#orig (get-env :dependencies)]
(set-env! :dependencies ~deps)
(let [#ret ~task]
(set-env! :dependencies #orig)
#ret)))
it's rhomboid so you know it's good
yup, rhomboid 👌
it's a level of macro mastery that is truly impressive
we can't praise micha too much or else he might retire and leave us with all these macros
i wonder if boot should have a dynamic var that when bound would cause boot to not actually load deps when you set-env!
that would do the setting and restoring without actually adding new jars to the classpath
-1 exposing dynvars as api, +1 macro
but yeah that would be sweet
we can make a patch i think for now, @malcolmsparks if that would help you
a snippet that you can put in your build.boot that patches the aether stuff and adds this macro
i wonder if deftask isn't the place to hang these things
like in the precondition hole
i see
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
like you couldn't wrap a task constructor with this and then return what the constructor did
i guess it works as long as the resolution is happening in the task constructor
because the bindings are only known by the code that instantiates the task, not by the task itself
(defn cool []
(with-env ...
(foo-task :opt val)))
(comp
(cool)
(bar-task :opt val))
would that work?
it seems that the gotcha is the deps stuff needs to happen in the foo-task constructor
not a gotcah i guess, that is the recommended place, but so far we've never depended on it anywhere
ok i see, yes they are equivalent
ok i'm almost out of objections
binding-env
maybe is better than with-env
since it pushes and pops bindings in a way
ok one more question @alandipert
ok i had a thought about what the Right Thing is
like taking a step back, maybe the underlying thing that sucks is that filesets can't go between pods
if they could, there would be no reason to pollute your global env before you started your task pipeline
currently the model is simple, the tasks create pods by building on the env of the main pod
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?
both of those tasks will create their pods using the version of core.async they see in the main pod's env
(comp
(binding-env
{:depdencies '[[org.clojure/core.async "1.2.3"]]}
(A ...))
(binding-env
{:dependencies '[[org.clojure/core.async "4.5.6"]]}
(B ...)))
an equivalent way to do it would be to run the task function in a pod
it seems like this binding-env thing is a poor man's pod
necessary only because filesets can't go between pods
that even looks like you're making a pod
except you're not, you're doing a workaround thing
or maybe in a pod the boot.core you see is a bridge ns that de/serializes
that would work, if you add some kind of locking semantic when you add it to the pipeline
the only problematic thing in boot.core is set-env! right?
like the singleton environment is what boot.core represents
i think so
also the fileset system
that's the other resource
in any case this feels like a 3.0 thing
i like the idea of cutting down the places with essential global state to a few specific places
yeah and when you call functions in it you're enqueing things for execution in the lower level java singleton enviro
maybe put the binding-env thing in for now but mark it deprecated lol
yeah i was thinking about how the Ideal Bootfile
only uses maven to pull in names of tasks
but lots of times that's not what you want
like a big project, it is what you want
everything you're doing you factor into a task outside your build.boot
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
maybe a new kind of build.boot?
like system.boot or something
that's true
and i think it's safe to fake the dependencies at least, becuase task libraries don't have transitive deps
so like the task itself won't use core.async in the task namespace, it'll use core.async in a pod
probably also too complicated but another seam is boot-in-boot
that would require a way to stitch boots together
which seems like what @malcolmsparks could use
seems easy-ish
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-envWhen the set-env! returns the previous state, the clojurescript & such is being restored.
yeah we need to implement the dynamic var that will disable actual loading of the "fake" dependencies in the core pod
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?
> 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.
> 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.
(comp
(with-env
{:dependencies '[[foo/bar "1.2.3"]]}
(some-task :option some-option))
...
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?
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.)
(comp
(with-env
{:dependencies (mangle-deps (get-env :dependencies))}
(cljs :optimizations :advanced))
...
(with-env
cljs-env
(cljs :ids #{"edge"} :optimizations :none))
=> java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol(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"}}])])
(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#)))
@micha: After removing the second apply, => java.lang.RuntimeException: Unable to resolve symbol: cljs-env in this context
@micha: Yeah, I made a stupid mistake. The let binding is pretty unwieldly at this point.
@micha ish.. for some reason om isn't being pulled in (possibly other cljs deps too)
{: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..the boot-cljs task should be just adding its own deps to whatever it gets from (get-env)
or boot.pod/env
boot task-with-macro show --list-pods
will show the names if what i wrote above isn't correct
https://gist.github.com/SevereOverfl0w/13e93b7fcadbac8ba741 I'm not doing anything obviously wrong in frontend am I? Just running the show thing now
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.
With the show, how do I do that given that the frontend is crashing? Take cljs out of the with-env?
@micha: https://gist.github.com/SevereOverfl0w/965f4f63dc98b552f1e2 what I'm looking at
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?
@taylor.sando: build the project with boot
@taylor.sando: stupid answer but I think it is actually the easiest/quickest way
@micha did the repl, checked the classpath, old versions of clojurescript are being used, for sure.
You mean build om with boot?
@taylor.sando: yeah, and then use the checkout task in your own project boot checkout -h
@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.
Is it possible we've accidentally prevented additional dependencies from being pulled in?
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"
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"
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"
look here: https://github.com/adzerk-oss/boot-cljs/blob/master/src/adzerk/boot_cljs.clj#L95-L97
You think just overriding that is best for cljs for now? should I look at modifying the task in a fork?
the best thing is probably to save the (get-env)
in the outermost let binding of the cljs task
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
I wonder if it was done for the possibility of dependency hot loading... Even that seems a bit of a stretch though
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
@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?
@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?
@juhoteperi is the boss of the boot-cljs project
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
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?
Lol perfect, I knew it was easy 😄
ah ok cool
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
but no, I have the info to set System.exit
https://github.com/boot-clj/boot/blob/master/boot/base/src/main/java/boot/App.java#L385-L397
nice, can use getMessage and set my own code
perfect!
you have thought out everything already 😄
I have to say that in theory the parallel testing stuff could be generalized to parallel boot tasks
but I will maybe leave this to someone else, gotta switch to some other stuff soon
the code is there already, just need to rename stuff 😄
as you were saying earlier I am using CountDownLatch for syncing
(btw please review the code because concurrency is always tricky, especially the sync-map
part)
was the conclusion here now that scope provided for piggieback is a bad idea? https://github.com/cemerick/piggieback/issues/70#issuecomment-179407012