"Because I just... don't feel like managing two config files... *sigh*..."
slothcfg for Leiningen 2 fills in the missing features in Leiningen 2's profile support:
- Makes the
project.clj
file available to your code at runtime so that you can use it as a config file! - Build profiles for Leiningen that can be set and remain in effect until unset.
- Built-in templates to create .cljs, .cljx or .cljs config files.
To install slothcfg, add the following to your project map as a plugin:
[slothcfg "1.0.1"]
That is all you need. But you will probably also want to add two
directories to your .gitignore
file. The first is the directory
.slothcfg
, which will be in the same directory as your
project.clj. This directory holds the currently active profile. The
second is the namespace that is automatically generated by slothcfg
with your profile values. In most of the examples above, you'd want to
add "src/cfg/current.clj" or possibly "src/cfg" to your .gitignore
, if there are no other files you will have in src/cfg
that you wish to check into git.
The first step is learning about Leiningen's profiles, in the "Profiles" section. slothcfg only provides user interface to turn profiles on and off, and to make them available to the code in the project itself, so you need to understand how they work.
The only user-operable way of controlling profiles in use is using
Leiningen's built-in with-profile
task, which requires you to list
all the profiles you'd like to have in effect for the task that is
given as its argument.
When slothcfg is installed, you can get a list of the currently
active profiles by doing lein profiles
:
[prompt]$ lein profiles
debug
default
offline
test
user
Current sticky profiles:
Here, slothcfg has modified the built in profiles
task to also
print out the currently active sticky profiles. In this case, since
none have been set, there are no current sticky profiles. We can set a
few profiles using slothcfg set
:
[prompt]$ lein slothcfg set test stage
Warning: Unknown profile :stage is being set active.
Current sticky profiles: #{:test :stage}
Now two profiles have been set to active, :test
and
:stage
. slothcfg has warned that it cannot find any profile called
:stage
, as it isn't present in the project map. But it has still set
the profile to stick.
If we set :stage
by mistake, we can unset that profile using the slothcfg unset
command:
[prompt]$ lein slothcfg unset stage
Current sticky profiles: #{:test}
If we wish to remove all sticky profiles at once, we can simply call
slothcfg unset
with the --all
flag:
[prompt]$ lein slothcfg unset --all
All profiles unset.
[prompt]$ lein profiles
debug
default
offline
test
user
Current sticky profiles:
Note that none of this is modifying the project map. It is simply
stashing a bit of state that will be automatically applied when you
run Leiningen tasks. This state is stored in the file
.slothcfg/current
in your project root. This file can be deleted
at any time with no ill effect (other than unsticking all the profiles
that were set.
Finally, note that the built-in with-profile
task still works the
same as it ever did. Any profiles it sets are added to the set of
sticky profiles already in effect, as sticky profiles are as if there
is an implicit with-profile
with those tasks.
The second half of slothcfg is making the project map, with all
active profiles merged in, available to the project itself, in
addition to within leiningen's own process. It does this in part by
outputting a Clojure source file into a location of your choice (by
default {first of :source-paths project key}/cfg/current.clj
) that
contains the project map. Any code that is interested in the project
map, whether it is running in Leiningen, in your project, or in a JAR
built by Leiningen with slothcfg installed, can access it by loading
that namespace and accessing the project
variable in it.
As an example, suppose you run the repl
task:
[prompt]$ lein repl
Connection opened on localhost port 4005.
Then within the repl, you can do the following:
user> (use 'cfg.current)
nil
user> (prn project)
{:compile-path "/path/to/my-great-project/target/classes", :group "slothcfg", ...}
nil
So we can see that we were able to use the cfg.current
namespace and
find the entire project map in the project
var from that
namespace. As you would expect, you can now write code that require
s
the cfg.current
namespace and changes its behavior based on its
contents. This code will continue to work even when a JAR is built
from this project. The project map available in the JAR will be based
on the configurations that were included when the JAR was built
(either through sticky profiles or the with-profile
task or none,
depending on which is the case).
You can change the behavior of slothcfg by setting some values in the
project map. slothcfg's configuration goes in the :slothcfg
key, which
should contain a map of option names to their values. Here are the current
keys:
:config-source-path
- Set this key to the path to the source directory to output the project map namespace into. Note that this is the location of the source directory, not the full path of the file the namespae is in; that will be named automatically based on the namespace's name.- Default: the first entry in the
:source-paths
key in the project.
- Default: the first entry in the
:file-ext
- String with the file extension for the saved file. Useful for integration with cljx.- Default: ".clj" if not specified
:namespace
- Set this key to the name of the namespace, as a symbol, that you want the project map to be output to.- Default:
cfg.current
if not specified
- Default:
:var
- Set this key to the name of the var, as a symbol, that you want the project map to be output to.- Default:
project
- Default:
:verbose
- Set this key to true if you'd like slothcfg to print out which profiles are included whenever a task is run.- Default:
false
- Default:
:keyseq
- A keyseq to the subset of the project map you want to output. For example, set to[:config]
to output only everything under:config
.- Default: [] ; empty. the entire project map is output.
:middleware
- A function that takes a project map and outputs a transformed version of it. Note that if:keyseq
is specified, it operates on that subset.- Default: No filtering is done. Equivalent to:
(fn [p] p)
- Default: No filtering is done. Equivalent to:
:template
- Optional string specifying a custom template on the classpath for use with stencil. Overrides the default templates that slothcfg uses based on the value of :file-ext (currently: .clj, .cljx, .cljs).:never-sticky
- If specified, this should be a vector containing a list of profile name keys that should never be set sticky. For example, you can put your production profile in this key to make sure you don't accidentally set yourself into a production profile.
So for example, if the project map has the following map in the :slothcfg
key:
:slothcfg {:config-source-path "src/main/clojure"
:namespace myproject.config
:var config
:keyseq [:config]
:verbose true}
Then the project map will be at myproject.config/project
, which is
in the file src/main/clojure/myproject/config.clj
. When you run the
command:
[prompt]$ lein with-profile test profiles
Performing task with-profile with profiles (:dev :user :default)
Performing task 'profiles' with profile(s): 'test'
Performing task profiles with profiles (:test)
debug
default
offline
test
user
Current sticky profiles:
Here you can see the verbose statements of slothcfg mixed in with
the statement output by the with-profile
task. First the
with-profile
task has its profiles output by slothcfg, before it
runs. Only the default Leiningen profiles are in effect when it
runs. Then it prints out its statement that it is running the
profiles
task with the test
profile. Then slothcfg prints out
the profiles in effect when the profiles
task runs; just the test
profile. At the end, you can see that there were no sticky profiles in
effect. If we add the prod
profile as a sticky profile:
[prompt]$ lein slothcfg set prod
Performing task slothcfg with profiles (:dev :user :default)
Current sticky profiles: #{:prod}
[prompt]$ lein with-profile test profiles
Performing task with-profile with profiles (:dev :user :default)
Performing task 'profiles' with profile(s): 'test'
Performing task profiles with profiles (:test :prod)
debug
default
offline
test
user
Current sticky profiles: #{:prod}
Here we can see that the prod
profile was added to the running of
the profiles
task because it was set sticky, and the test
profile
was added by the with-profile
task.
Since all of this extra output is controled by the :verbose
key in the :slothcfg
configuration map, you can actually make yourself a profile that has the :verbose
key to true in a :slothcfg
map, and then set that profile to by sticky:
;; In project.clj...
:profiles {:verbose-slothcfg {:slothcfg {:verbose true}}}
Then
[prompt]$ lein slothcfg set verbose-slothcfg
will make it so that you can switch slothcfg from verbose output to quiet output by setting or unsetting the verbose-slothcfg
profile.
[prompt]$ lein slothcfg set verbose-slothcfg
Current sticky profiles: #{:prod :verbose-slothcfg}
[prompt]$ lein jar
Performing task jar with profiles (:dev :user :default :prod :verbose-slothcfg)
Created /path/to/my-great-project/target/my-great-project.jar
slothcfg was forked from Configleaf because it appeared to be inactive (it hadn't been updated in over a year). I decided to fork this project and give it a new name so that folks can include new updates via Leiningen. I decided to go this route instead of submitting a pull request because the configleaf project has two outstanding pull requests already (one of them over a year old). The changes in those pull requests have been incorperated into slothcfg (in fact, slothcfg is actually a fork of Justin's pull request).
- In your project.clj, remove
configleaf.hooks
from:hooks
and change the configleaf entry in your:plugins
to match what's listed in the Installation section. - Search your entire project and replace ever occurrence of "configleaf" with "slothcfg".
- Rename the invisible
.configleaf
directory at the root of your project to.slothcfg
Remember that the set-profile
and unset-profile
tasks are now replaced by
slothcfg set
and slothcfg unset
. This was done to future-proof slothcfg in case
another plugin (or leiningen itself) wants to use those task names.
-
Version 1.0.1 (By: Greg Slepak / @taoeffect)
- Renamed project to slothcfg so that users can pull new features from Clojars.
- Removed all use of :use (it's bad, mmm'k?)
- Removed robert-hooke dependency because it comes with leiningen 2.
- Consolidated the
set-profile
andunset-profile
tasks under a genericslothcfg
task to future-proof slothcfg. - Added :file-ext option to specify config file extension.
- Added :template option to allow the option of providing your own mustache template.
- Added :middleware option to optionally transform the project map.
- Added templates for .cljx and .cljs :file-ext.
- Updated .clj template to use 'defonce' now.
- Templates now store config map in an atom to allow for updates within the project.
- dissoc :checkout-deps-shares from the project map to fix an incompatibility with Leiningen 2.3.0 that caused an "Unreadable form" RuntimeException.
- Included @ninjudd's PR to configleaf to add :keyseq and :var options
- Restructured and updated text in README.md
-
Version 0.4.7 (By: Justin Balthrop / @ninjudd)
- remove unused v1 legacy methods
- Add support for outputting a subset of the project map via :keyseq option
- Added :var option
-
Version 0.4.6
- Implement the
:never-sticky
configuration key.
- Implement the
-
Version 0.4.5
- Bug fixes; remove one of the hooks which is no longer necessary in lein2. Don't use earlier 0.4 series versions (harm is bounded to extra files being added to JARs or lein tasks failing).
-
Version 0.4.3
- Minor update to also add slothcfg itself to dependencies, fixes similar bugs.
-
Version 0.4.2
- Minor update to automatically add leiningen-core to dependencies, fixes certain tasks were hooked but ran in project.
-
Version 0.4.1
- Minor update to ensure that project map metadata is baked along with the project map.
-
Version 0.4.0
- Extensive rewrite to work with Leiningen 2.
-
Version 0.3.0
- Renamed and reorganized the project map. Should be easier to explain and use now.
-
Version 0.2.0 (By: David Santiago / @davidsantiago)
- Addition of Java system properties to configurations.
- Changes to configuration map format to allow system properties.
Copyright (C) 2011 - 2013
Distributed under the Eclipse Public License, the same as Clojure.