I got it. Thanks.
If I want to use logger in ig/halt-key
, then return {:server server :logger logger}
is the way?
Yep
Thank you very much!
In Integrant 0.8.0-alpha2 I've added a resolve-key
multimethod that might be useful if you just want to use the server in references.
Though it's still experimental functionality.
That sounds great.
I don't understand how to properly separate dev config from prod config in Duct 0.11. I'm trying to introduce Duct into an existing (minimal) project sort of piece by piece. Is there an example project somewhere I could look at? For example, I'd like to run :duct.compiler/sass
only in dev.
Well, this is probably one problem, at least:
Syntax error (ClassCastException) compiling at (dev.clj:35:3).
class duct.logger.timbre.TimbreLogger cannot be cast to class clojure.lang.IFn (duct.logger.timbre.TimbreLogger is in unnamed module of loader clojure.lang.DynamicClassLoader @36f39f6a; clojure.lang.IFn is in unnamed module of loader 'app')
clojure.core/eval core.clj: 3214
...
shadow.user$eval29750.invoke : 1
shadow.user$eval29750.invokeStatic : 1
...
dev/eval29754 dev.clj: 35
integrant.repl/go repl.clj: 54
integrant.repl/prep repl.clj: 16
...
clojure.core/alter-var-root core.clj: 5505
clojure.core/alter-var-root core.clj: 5510
...
integrant.repl/prep/fn repl.clj: 16
dev/eval29741/fn dev.clj: 28
duct.core/prep-config core.clj: 193
duct.core/build-config core.clj: 182
duct.core/fold-modules core.clj: 145
integrant.core/fold core.cljc: 282
clojure.core/reduce core.clj: 6827
...
integrant.core/fold/fn core.cljc: 282
duct.core/fold-modules/fn core.clj: 145
The same error is actually reproducible if you just add this into the config.edn
of a clean Duct Leiningen template:
:duct.logger/timbre {:level :info
:appenders {:duct.logger.timbre/println #ig/ref :duct.logger.timbre/println}}
:duct.logger.timbre/println {}
@weavejester Do you want an issue for this, too? I guess it belongs in duct-framework/logger.timbre
?
I think the same error occurs whenever ig/init-key
returns something that satisfy ifn?
.
Hi
Have you moved all of your non-module keys into profiles? It sounds like you haven't done that step.
Well, it's unclear to me which keys are module keys and which are non-module keys.
Anything beginning with :duct.module
or :duct.profile
is a module key.
Okay. So :duct.logger/timbre
should go under :duct.profile/prod
?
In 0.10 and below, modules were mixed with non-module keys. In 0.11, there separation is explicit.
Yes, that's right.
Or can it also go under :duct.profile/base
?
Assuming you want to change the default :duct.module/logging
settings.
It depends if you want the configuration in all profiles, in which case put it in base, or just in production, in which case put it in prod.
Okay. I think I gave that a try already, but I probably messed something up.
Let me give it a go.
Well, I have a config.edn
like this:
{:duct.profile/base {:duct.core/project-ns <http://foobar.server.app|foobar.server.app>
:duct.logger/timbre {:set-root-config? true
:level :info
:appenders {:duct.logger.timbre/println #ig/ref :duct.logger.timbre/println}}
:duct.logger.timbre/println {}}
:duct.profile/dev #duct/include "dev"
:duct.profile/local #duct/include "local"
:duct.profile/prod {}
:duct.module/logging {}}
And then I do (repl/set-prep! #(duct/prep-config (read-config) [:duct.profile/dev]))
and (go)
and I get Assert failed: (map? config)
from ig/prep
.
But I guess there must still be something wrong with my config...
Does the assert have a stacktrace associated with it?
Assert failed: (map? config)
Syntax error compiling at (/foobar/dev/src/dev.clj:45:3).
at clojure.lang.Compiler.load(Compiler.java:7647)
at shadow.user$eval30043.invokeStatic(Unknown Source)
at shadow.user$eval30043.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.eval(Compiler.java:7131)
at clojure.core$eval.invokeStatic(core.clj:3214)
at clojure.core$eval.invoke(core.clj:3210)
at clojure.main$repl$read_eval_print__9068$fn__9071.invoke(main.clj:414)
at clojure.main$repl$read_eval_print__9068.invoke(main.clj:414)
at clojure.main$repl$fn__9077.invoke(main.clj:435)
at clojure.main$repl.invokeStatic(main.clj:435)
at clojure.main$repl.doInvoke(main.clj:345)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at nrepl.middleware.interruptible_eval$evaluate$fn__20103.invoke(interruptible_eval.clj:87)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.core$apply.invokeStatic(core.clj:665)
at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1973)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1973)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:85)
at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:54)
at nrepl.middleware.interruptible_eval$interruptible_eval$fn__20146$fn__20149.invoke(interruptible_eval.clj:218)
at nrepl.middleware.interruptible_eval$run_next$fn__20141.invoke(interruptible_eval.clj:186)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.AssertionError: Assert failed: (map? config)
at integrant.core$prep.invokeStatic(core.cljc:412)
at integrant.core$prep.invoke(core.cljc:412)
at integrant.core$prep.invokeStatic(core.cljc:417)
at integrant.core$prep.invoke(core.cljc:412)
at duct.core$prep_config.invokeStatic(core.clj:195)
at duct.core$prep_config.invoke(core.clj:184)
at dev$eval30027$fn__30028.invoke(dev.clj:41)
at integrant.repl$prep$fn__29833.invoke(repl.clj:16)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Var.alterRoot(Var.java:308)
at clojure.core$alter_var_root.invokeStatic(core.clj:5510)
at clojure.core$alter_var_root.doInvoke(core.clj:5505)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at integrant.repl$prep.invokeStatic(repl.clj:16)
at integrant.repl$prep.invoke(repl.clj:14)
at integrant.repl$go.invokeStatic(repl.clj:54)
at integrant.repl$go.invoke(repl.clj:53)
at dev$eval30047.invokeStatic(dev.clj:45)
at dev$eval30047.invoke(dev.clj:45)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.load(Compiler.java:7635)
... 27 more
What does your dev.edn
file look like?
{:shadow.cljs/watch {:id :app}
:duct.compiler/sass {:source-paths ["resources/sass"]
:include-paths ["node_modules"]
:output-path "resources/public/css"}}
Hmm... does dev.edn
need to have duct.profile/dev
as the top-level key?
No, because it's included via #duct/include
OK.
The resource is literally inserted verbatim where the reader tag is.
Gotcha.
It must be something odd in my project because if I copy-paste those same config files into a clean Leiningen Duct template, I don't get that error.
I'll keep digging. Many thanks for the help.
Okay, weird, I'm not seeing anything obviously wrong here. Would you mind running a couple of commands for me?
Not at all.
Shoot.
FWIW, this is not a Leiningen project I'm working on. It's a deps.edn
project. Not sure whether it matters.
(-> (read-config) (doto ig/load-namespaces) (build-config [:duct.profile/dev]))
Oh, another thing to try is to shut down your REPL, clean your target directory, and restart your REPL.
OK.
Since multimethods can be missed by reloads.
That yields nil
.
(Assuming build-config
is duct.core/build-config
.)
Yep
Does the same thing occur when you restart your repl?
Yes. I cleared everything I can think of.
Are the dependencies the same as the ones in the template?
:dependencies [[org.clojure/clojure "1.10.0-beta4"]
[duct/core "0.7.0-beta2"]
[duct/module.logging "0.4.0-beta1"]]
No! I had the wrong version (0.3.1) of duct/module.logging
. :picard-facepalm:
Aha!
That solved the assertion error. Many thanks!
No problem 🙂
Actually, let me open an issue for this to give this a clearer error message.
As a bonus, I now understand much better how the whole thing works. The only thing I'm still not 100% clear on is the module/non-module distinction. For example, this page https://github.com/duct-framework/duct/wiki/Modules lists both logger.timbre and module.logging as modules, but logger.timbre actually isn't…?
Oh, that page wasn't added by me 🙂
I'll make a note to fix that page before release.
Great!
With regard to modules/non-modules, anything beginning with :duct.module
or :duct.profile
is a module. In 0.11, a module is a function that transforms a configuration, so config -> config
.
That latter explanation was what I was looking for — thanks!
In 0.11, a configuration of modules is initiated into transformation functions, and then applied in dependency order to an empty map. This produces a new configuration, which is then initiated.
You can think of Duct's configuration as a "higher-order configuration", in the same way that we have higher-order functions.
Duct's config initiates into an Integrant config, which is then initiated into a system.
Right, so modules transform configurations and non-modules are things that contain stateful resources etc.
Right.
Gotcha.
Also, everything works great now :bananadance:
The idea is that you can write a module that adds a whole bunch of configuration so you can abstract common patterns of config.
In the same way that higher-order functions allow abstraction of code patterns, like map, filter, reduce, etc.
Yes, that makes sense.
Might be useful to add at least one non-module key in the example here https://github.com/duct-framework/duct/blob/master/UPGRADING.md to make things clearer.
Where it says ;; ... more non-module keys
, maybe have e.g. :duct.logger/timbre
to make it clear you have to put it there.
Also, that page could maybe also make the module/non-module distinction explicit.
Those are good ideas.
I have read https://github.com/duct-framework/duct/blob/master/UPGRADING.md and I've managed to set up things so that when I do (duct/read-config "config.edn")
, it includes the contents of my dev.edn
under the duct.profile/dev
key, but none of that is being executed.