This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-13
Channels
- # admin-announcements (1)
- # beginners (53)
- # boot (355)
- # braid-chat (4)
- # cider (15)
- # cljsjs (3)
- # clojure (88)
- # clojure-austin (1)
- # clojure-new-zealand (4)
- # clojure-russia (46)
- # clojure-uk (7)
- # clojurescript (61)
- # component (2)
- # cursive (3)
- # data-science (5)
- # datomic (6)
- # dirac (49)
- # editors (8)
- # emacs (15)
- # funcool (15)
- # jobs (1)
- # ldnclj (10)
- # melbourne (1)
- # off-topic (14)
- # om (61)
- # om-next (2)
- # onyx (32)
- # re-frame (28)
- # reagent (19)
- # test200 (1)
- # vim (3)
Is it possible to change the boot env for a single task run? E.g. a build
task can’t be called from a repl because I might have dev-only source-paths added, so I’d like to be able to make it set a specific source-path for building without affecting the source paths in the repl as a whole. Is this possible?
may be an obvious question, but I’m only a day into boot and haven’t been able to figure out how people handle these situations.
Like-wise for wanting to run tests from the repl without adding the test sources into the main repl
It may just be that I don’t grok pods, but I thought I’d seen that a REPL can’t be in a pod). Furthermore, I don’t see how that fixes the problem of runnign tasks that have different source-path needs. Like running a (boot (tests))
then (boot (build))
as the former will affect the contents of the built jar
so multiple reps are you meaning having multiple processes or having a repl that I exit every time I need to run a boot task in the main repl, then re-enter?
because it's rare to be both developing, testing, and making production builds all at the same time
re: repl in pod, https://github.com/boot-clj/boot/wiki/Cider-REPL seems to allude to repls being special and that they can’t run in a pod because it needs to be in project context AND have access to boot context
@micha: frankly, I’m probably just confused. Boot seems to try to be quite functional but then has a global shared, mutable, env
@micha: use-case where I first ran into this: a build
task which first runs all the tests to check that it’s passing before building. The former corrupts the env which then makes the build artifact include tests
I am using boot-test. It doesn’t see my test paths unless I first add them to the env though
@micha: I was precisely expecting boot-test
to provide a way to declare test paths for it to use (I was also expecting it to have a task that would only call the next-task if the tests passed, but instead I'd just use the version that throws an exception, which seems good enough)
https://github.com/SevereOverfl0w/boot-snippets/blob/master/src/io/dominic/boot_snippets.clj#L14-L43
so I suppose what you are saying is that I could make my own test task which creates a pod, adds the path, then calls boot-test’s task, which I suppose creates yet another pod?
because each clojure runtime creates the classes and interfaces for core collections etc at runtime, dynamically
so the class clojure.lang.PersistentVector in one pod is totally different from the class named clojure.lang.PersistentVector in another pod
Yeah, that’s how I already understood it, but probably not deeply enough to grok all implications. You earlier stated that boot-test
creates it’s own pod so was vamping on that idea a bit
@micha: in the “boot for lein users” pages I don’t see dev dependencies listed much. From reading a bunch of boot scripts in different projects it seems like some people are just adding deps to the env in certain tasks (which I have been) while others are adding them to the root env but with scope “test”. Are there any implications of one approach or the other or are they specifically for different use cases that I haven’t picked up on yet?
@micha: well for example I don’t need asset autobuilding in production (i’d precompile it all to be served), or in dev I might want a ring middleware which displays extra debug information on exceptions, but in production I wouldn’t expose exceptions at all
micha: I do too but it’s common practice at least in lein land to not even include those dependencies in, for example, an uberjar for prod
so in my case, I have a dev-only source-path which might expose middleware to be wired up and require the dev-only middleware
but since the “for lein users” doc pages don’t explicitly make that connection, I wasn’t 100% sure I was on the right path there
I think :scope “test”
is the clearest way I’ve seen so far and it sounds like there isn’t a gotcha with that that I’ve missed so should be a-ok.
in general we have tried to avoid adding things like directly specifying dependencies to tasks etc
yeah it works fine for “dev dependencies” (which aren’t test in the sense they aren’t strictly there to support any kind of automated tests) it’s just the name (which I understand is a maven thing) through me momentarily
for uberjars i've been having very good results using a very small shim that gets AOT compiled, leaving my actual application as source
this: https://github.com/boot-clj/boot/wiki/Circumnavigating-Watch-and-AOT-Compilation-Limitations
yeah I suppose with :aot :all
things you don’t require
won’t get aot’d so simply wiping any /.clj[cs]?$/
files is enough to remove dev deps anyway
the main idea there is
(ns foo.main
(:gen-class))
(defn -main [& args]
(require 'foo.core)
(apply (resolve 'foo.core/-main) args))
micha: yeah I’m actually doing this incidentally anyway, though I’m aot’ing everything atm
uberjars get a huge benefit from incremental compilation because boot can cache everything
if you’re watch
’ing only right? My understanding is that boot doesn’t maintain any kind of cross-process cache
the uber task uses the global one, with the hash key being the md5 hash of the jar contents
so tl;dr boot will cache things, but only when there is a foolproof way to invalidate the cache
(none of this is really important to me right now, FWIW, I’m just curious and playing with boot in a fresh project so I don’t have any strict needs or anything)
also a single namespace will be compiled into multiple .class files, which is also weird and hard to think about
i just remember having a terrible time with caching in every build tool i've ever used pretty much
it's extremely depressing to spend an hour debuggin some crazy problem that turns out to be caused by stale artifacts
or your thing works and you work for a few hours, then you clean and rebuild and everything is broksn
anyway thanks for the discussion. It’s been very helpful. Unfortunately I have to go to some grocery shopping and other real life things.
(deftask api-test []
(merge-env! :source-paths (get-in config [:api :test :source-paths])
:dependencies (get-in config [:api :test :dependencies]))
(require 'adzerk.boot-test)
(let [api-test (resolve 'adzerk.boot-test/test)]
(println "Hello World")
(comp
(watch)
(api-test)
#_(report-test))))
Can you run this in the repl? Seems like when I run (api-test), it returns the comp function
I mostly just want to save memory by not having to run a separate jvm instance for testing
@taylor.sando: does (boot (api-test))
not work in the repl?
I wasn't running the boot before api-test. Can you run the watch task in a future or delay so that it doesn't take over the repl?
Does boot-test always have a really long delay to run? I'm getting 16 seconds for just one test.
It's a dependency, but not involved in the one test I just made
Does loading datomic slow things down?
Ya taking out the requires speeds things up a lot
I added :requires #{'datomic.api}
, but it didn't really speed things up.
The test is just (is (= 5 5)) at the moment. I removed the datomic-specific tests
I'll just run a separate instance and use run-all-tests with the namespaces, it's not absolutely critical that I have this all in one jvm
I can run clojure.test/run-all-tests without the same slowness. The separate jvm is just because I'm using mount at the moment, and you can't really have two instances of mount going. There is yurt, but it hasn't been updated to use the latest mount changes.
@micha with-env
from boot-snippets
doesn’t seem to do anything. I did a (show :environment true)
inside and outside the block and the env seems unchanged
requiring pedestal seems to really slow things down on the initial run
micha: egh actually I think it’s the way I’m using env
. It really has to wrap the invocation of a specific task but I’m wrapping a whole composition of tasks which means when they actually are called the environment is probably already reset
tasks are kind of like stateful transducers, like the way the creation of the transducer is done separately from the use of it in a pipeline
I mean the with-env
macro is really simple, so I am kinda surprised that this still has a :source-paths
of just #{“src”}
:
(with-env
{:source-paths #{"src" "test”}}
(show :env true))
hmm well this is what I was originally trying, but run-tests
still does not use the altered source-paths:
(with-env
{:source-paths #{"src" "test"}}
(comp (watch)
(bt/run-tests)))
I’m guessing that’s because it’s been reset by the time it actually runs as mentioned above
if you wrap that with the with-env
macro it will affect the env when the pod is created
i've only really used a macro like that when i had some annoying dependency conflicts and i wanted a shortcut to get something working temporarily
yeah I can tell I’m going against the grain here, but I guess I’m just used to a certain workflow.
(comp (watch) (with-env {…} (run-tests)))
probably might work in some way, but then I imagine the watch isn’t watching the tests, right?
it doesn't really know anything about the tasks it will pass the fileset to for the rest of the pipeline
So recall I’m trying to avoid polluting the caller of a task with changes needed for the task. I started with a (set-env! :source-paths #(conj % “src”))
in the test task
but since I’m having a task which is a “dev” mode entry point, which starts a repl with just src and dev src-paths and an auto test runner with src and test paths, it’s getting messy
I’ll take anything that lets me have a workflow of something like boot [cider] dev
which starts an nREPL server that just has “dev” and “src” on the source-paths and starts a watch and test run with both “src” and “test” in source-paths
It’s a matter of purity I guess. Each task should have the same classpath when run as a group as when run individually
i don't really have any philosophical preference, i just want to make computer programs
really, it just bothers me. Probably rooted in my background with languages like Ruby where when A loads B and then loads C somehow C knows about B and it means a lot of spooky action at a distance so I have a keen aversion to that kind of pollution
in any case, it does seem strange to me that the fileset etc is strictly functional but the environment is not
you should give the straightforward alltogether way a shot and see how it goes, maybe you'll enjoy it
from an ergonomic perspective as a first time user, it was very surprising. I expected a change in env to propagate to a task and it’s sub-tasks but not to the previous task
Maybe not strictly functional but the method of passing the input and output fileset between tasks is still pretty functional, compared to the environment
micha: sure but it was surprising to me that there wasn’t a great way to manage the state of the environment
but the immutable fileset object is useless if it doesn't directly relate to the actual mutable classpath
but anyway you're going to be interacting with java things that expect to use a noremal java classpath
Yeah I understand that. My desire for separation of the class path in these different modes is probably because I’ve picked up from projects like luminus and examples in system/mount, etc, patterns like declaring the same namespace in different source-paths to do things like vary configuration (e.g. diff middleware definition) with minimal conditionals. That’s really really nice, but it requires being able to not include a certain path in the source-paths at certain times
you can use pods to have separate cojure runtimes each with their own different dependencies
this first actually bit me because my build task wouldn’t run from the repl because my dev-only user.clj depended on boot but was getting accidentally included into the jar because “dev” was on source-path and then obviously not compiling
running (boot (build))
complained about not finding boot.core
if AOT or similarly when later run if not AOT
it’s not needed in the uberjar. It’s not wanted. It was a side-effect of having dev
dir on the source-path
which is what prompted my quest to have the source paths specifically set during the execution of a certain task without pollution other parts
dev/user.clj
requires boot
. That’s a file I only expect to ever be relevant when developing locally, where boot is present
if your -main
function in the uberjar doesn't require
the user namespace there won't be a problem
unless you're doing AOT compilation for every namespace, in which case you'll probably have many weird issues to untangle
it’s probably just OCD on my part but it really bothers me that different tasks pollute the env of others
one thing about tasks that you will like is that no boot task every has transitiev dependencies
you can add as many boot task dependencies to your project as you want, you can never have a conflict
i'm not familiar with the patterns you describe about overloading namespace names and sort of metaprogramming in the project.clj by including or excluding them
It just always feel wrong whenever I have to go change some thing over there to change the behaviour of something over here. I’m chanigng source-paths
in a global env so that a task I’m about to call which will check that env for that config can act on it. It’s impossible to tell the watch
task, for instance, to watch “src” and “test” without telling everything everywhere that “test” is now a source-path 😞
I know the source-paths affect the classpath at certain points, but watch
, for example, doesn’t strictly need to modify the cp
For bootignore, how would you exclude all subdirectories? I've tried #"^src/dev/path/to/dir/.*?"
#"^src/dev/path/to/dir/*"
and #"^src/dev/path/to/dir"
What would the pattern look like if I want to include "src/main", but exclude "src/main/do-not-want"?
@bo: i haven't even realized there is a boot-figwheel
, but as i see it just brought over the same declarative config approach which proved to be a bit rigid in lein.
we just started using boot-reload
because about a year ago but it's still a bit unclear to me how to make it play well with hoplon and have sub-second updates without reloading the whole page.
@micha: What is the reason for this .git
check: https://github.com/boot-clj/boot/blob/master/boot/base/src/main/java/boot/App.java#L129-L133
Boot only reads build.boot
from workdir so I don't understand what is this projectdir supposed to be
Yeah, I don't know if causes any problems but looks like it might if the project is not git project
And doesn't seem very useful
Empperi mentioned some problems on IRC about Boot not reading boot.properties file (on Windows)
Doesn't look like that is the reason, but we wondered why does it exist
Hi there, to do multiple builds with boot-cljs, does it matter where in the project you put the *.cljs.edn
files? In the wild, I've seen examples with the edn files under src
, but I've also seen them under resources/js
.
Anything in the input-path of the fileset with a .cljs.edn extension will be available.
Anything in source-paths or resource-paths
Cool. Thanks @taylor.sando
It seems that boot-cljs
does the right thing in the default case (when no builds are specified). How does it know what the main
function is?
It doesn't. I will just require all namespaces in the fileset.
@juhoteperi: Ah, I see. Cool. So can I omit the init-fns
in the edn
file?
Ah I meant the case with no cljs.edn files
But yes, you can usually omit init-fns
If your namespaces have top-level calls to start the app, init-fns is unncessary