What does :provided mean in profiles.clj?
Asked Answered
B

3

10

Luminus right now is creating a profiles.clj with this content:

{:provided {:env {;;when set the application start the nREPL server on load
                  :nrepl-port "7001"
                  :database-url "jdbc:mysql://localhost:3306/mysqlkorma_dev?user=db_user_name_here&password=db_user_password_here"}}}

What does :provided do here? In environ's documentation it seems to point to having two entries, one for dev and one for test https://github.com/weavejester/environ.

Benzoin answered 17/7, 2015 at 8:26 Comment(0)
T
10

TL;DR: The provided profile is used in profiles.clj as an alternative to the dev profile, because if dev is used there it would overwrite the entire dev profile specified in project.clj.


The most common use of :provided is to specify dependencies that should be available during jar creation, but will be provided by the runtime environment. But I think here is used as a way to prevent the :env configured in profiles.clj (which is intended to not be committed into your source code repository) to overwrite the :env configured in project.clj.

Luminus would have used the :dev profile instead of :provided in profiles.clj, if it wasn't by the fact that they already put stuff in an :env entry in the :dev profile in project.clj which would be overwritten by what's in profiles.clj.

See this example repo. If you run it right away, without any change (with :provided in profiles.clj) the output will be:

› lein run
Hello, world
Db config: some:db://localhost

If you change :provided to :dev in profiles.clj, the output changes to:

› lein run
Hello, nil
Db config: some:db://localhost

They didn't get merged, but the :env in profiles.clj overwrote the :env in profile.clj


EDIT: I just found out that not only the :env entry would be overwritten if :dev was used in profiles.clj. The entire :dev profile would be overwritten. This is explained in the profiles documentation:

Remember that if a profile with the same name is specified in multiple locations, only the profile with the highest "priority" is picked – no merging is done. The "priority" is – from highest to lowest – profiles.clj, project.clj, user-wide profiles, and finally system-wide profiles.

So using :provided in profiles.clj is a little hack around the merging strategy of leiningen profiles.

It has at least one downside: if you need to define a :provided profile in project.clj to specify dependencies that will be available in the runtime environment it would be overwritten by the one defined in profiles.clj.

Tiddly answered 17/7, 2015 at 13:35 Comment(3)
Thanks for the detailed answer! In Luminus we ended up using a different hack so out of the box it has easy to modify hashmaps for both dev and test in both, project.clj and profiles.clj.Benzoin
Cool! Yes, you end up doing different hacks to be able to get to the promise of lein-environ of envs configurable in profiles.clj. I ended up not using lein-environ at all (but keep using environ). environ's README suggests to use :dev and :test in profiles.clj without explaining it would overwrite the same profiles in project.clj. Someone should edit that README explaining this little detail :)Tiddly
By the way, there's already an issue about this in environ with a bit of useful info: github.com/weavejester/environ/issues/15. The solution I like the most is to redefine the dev profile as :dev [:project/dev :profiles/dev]Tiddly
L
3

The :provided profile is used to specify dependencies that should be available during jar creation, but not propagated to other code that depends on your project. These are dependencies that the project assumes will be provided by whatever environment the jar is used in, but are needed during the development of the project. This is often used for frameworks like Hadoop that provide their own copies of certain libraries.

-- Reference

Lonni answered 17/7, 2015 at 13:28 Comment(4)
:provided is not being used here for dependencies, but to prevent the :env configured in profiles.clj to overwrite the :env configured in project.clj and get them merged insteadTiddly
It contains a map of profile-specific project properties, basically. It's a common use case to specify a value at :dependencies to, well, add jar-specific dependencies. But inclusion of other keys is possible too.Lonni
Sure. But the subtlety here is that luminus would have used the :dev profile in profiles.clj but is using :provided instead. If you create a new luminus project with mysql for example, you will get {:dev :env {:dev true :nrepl-port 7001}} in project.clj and {:provided {:env {:database-url "jdbc:mysql://localhost:3306/trylum_dev?user=db_user_name_here&password=db_user_password_here"}}} in profiles.clj. The strange thing here is why it's not using :dev in profiles.clj and I think my answer addresses that.Tiddly
@Tiddly interesting. Thanks,Lonni
S
1

As @nberger said provided is used to specify dependencies that should be available in your classpath, but will be provided by the runtime.

One particular case is libraries that if included in your project would get their signature messed up when creating the uberjar.

Such is the situation of BouncyCastle.

So your project.clj may look like:

:profiles {:dev {:dependencies [[org.bouncycastle/bcprov-jdk15on "1.50"]]}
           :provided {:dependencies [[org.bouncycastle/bcprov-jdk15on "1.50"]]}}

In this situation you say that for development you can use the library from maven repository, but on runtime it must be provided by the environment.

So the original jar file as-is, must be present in the classpath:

java -cp bcprov-jdk15on-151.jar:your-standalone.jar clojure.main
Sting answered 19/7, 2015 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.