leiningen/doc/PROFILES.md

174 lines
7 KiB
Markdown
Raw Normal View History

# Profiles
In Leiningen 2.x you can change the configuration of your project by
applying various profiles. For instance, you may want to have a few
extra test data directories on the classpath during development
without including them in the jar, or you may want to have Slamhound
available in every project you hack on without modifying every single
project.clj you use.
By default the `:dev`, `:provided`, `:user`, `:system`, and `:base`
profiles are activated for each task, but their settings are not
propagated downstream to projects that depend upon yours. Each profile
is defined as a map which gets merged into your project map.
You can place any arbitrary `defproject` entries into a given profile
and they will be merged into the project map when that profile is
active.
The example below adds a "dummy-data" resources directory during
development and a dependency upon "expectations" that's only used for tests.
```clj
(defproject myproject "0.5.0-SNAPSHOT"
:description "A project for doing things."
:dependencies [[org.clojure/clojure "1.4.0"]]
:profiles {:dev {:resource-paths ["dummy-data"]
:dependencies [[expectations "1.4.41"]]}})
```
## Declaring Profiles
In addition to `project.clj`, profiles also can be specified in `profiles.clj`
within the project root. Profiles specified in `profiles.clj` will override
profiles in `project.clj`, so this can be used for project-specific overrides
that you don't want committed in version control.
User-wide profiles can also be specified in `~/.lein/profiles.clj`. These will be
available in all projects managed by Leiningen, though those profiles will be
overridden by profiles of the same name specified in the project.
System-wide profiles can be placed in `/etc/leiningen/profiles.clj`. They are treated
the same as user profiles, but with lower precedence.
You can also define user-wide profiles within `clj`-files inside
`~/.lein/profiles.d`. The semantics within such files differ slightly
from other profile files: rather than a map of maps, the profile map
is the top-level within the file, and the name of the profile comes
from the file itself (without the `.clj` part). Defining the same
user-wide profile in both `~/.lein/profiles.clj` and in
`~/.lein/profiles.d` is considered an error.
The `:user` profile is separate from `:dev`; the latter is intended to
be specified in the project itself. In order to avoid collisions, the
project should never define a `:user` profile, nor should a user-wide
`:dev` profile be defined. Use the `show-profiles` task to list them.
If you want to access dependencies during development time for any
project place them in your `:user` profile. Your
`~/.lein/profiles.clj` file could look something like this:
```clj
{:user {:plugins [[lein-pprint "1.1.1"]]
:dependencies [[slamhound "1.3.1"]]}}
```
## Merging
2012-07-12 05:07:08 +00:00
Profiles are merged by taking each key in the project map or profile
map, combining the value if it's a collection and replacing it if it's
not. Profiles specified later take precedence when replacing, just
like the `clojure.core/merge` function. The dev profile takes
precedence over user by default. Maps are merged recursively, sets are
combined with `clojure.set/union`, and lists/vectors are
concatenated. You can add hints via metadata that a given value should
take precedence (`:replace`) or defer to values from a different
profile (`:displace`) if you want to override this logic:
```clj
{:profiles {:dev {:prep-tasks ^:replace ["clean" "compile"]
:aliases ^:displace {"launch" "run"}}}}
```
The exception to this merge logic is that `:plugins` and `:dependencies`
have custom de-duplication logic since they must be specified as
vectors even though they behave like maps (because it only makes sense
to have a single version of a given dependency present at once). The
replace/displace metadata hints still apply though.
Another use of profiles is to test against various sets of dependencies:
```clj
(defproject swank-clojure "1.5.0-SNAPSHOT"
:description "Swank server connecting Clojure to Emacs SLIME"
:dependencies [[org.clojure/clojure "1.2.1"]
[clj-stacktrace "0.2.4"]
[cdt "1.2.6.2"]]
:profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]}
:1.4 {:dependencies [[org.clojure/clojure "1.4.0-beta1"]]}})
```
## Activating Profiles
To activate a different set of profiles for a given task, use the
`with-profile` higher-order task:
$ lein with-profile 1.3 test :database
Multiple profiles may be combined with commas:
$ lein with-profile qa,user test :database
Multiple profiles may be executed in series with colons:
$ lein with-profile 1.3:1.4 test :database
The above invocations activate the given profiles in place of the
defaults. To activate a profile in addition to the defaults, prepend
it with a `+`:
$ lein with-profile +server run
You can also use `-` to deactivate a profile.
Activating different profiles will change your `:target-path` so that
elements which come from profiles don't spill over and contaminate
other profiles.
## Composite Profiles
Sometimes it is useful to define a profile as a combination of other
profiles. To do this, just use a vector instead of a map as the profile value.
This can be used to avoid duplication:
```clj
{:shared {:port 9229, :protocol \"https\"}
:qa [:shared {:servers [\"qa.mycorp.com\"]}]
:stage [:shared {:servers [\"stage.mycorp.com\"]}]
:production [:shared {:servers [\"prod1.mycorp.com\", \"prod1.mycorp.com\"]}]}
```
2012-08-24 12:34:22 +00:00
Composite profiles are used by Leiningen internally for the `:default`
profile, which is the profile used if you don't change it using
`with-profile`. The `:default` profile is defined to be a composite of
`[:base :system :user :provided :dev]`, but you can change this in your
2012-08-24 12:34:22 +00:00
`project.clj` just like any other profile.
## Debugging
To see how a given profile affects your project map, use the
[lein-pprint](https://github.com/technomancy/leiningen/tree/stable/lein-pprint)
plugin:
$ lein with-profile 1.4 pprint
{:compile-path "/home/phil/src/leiningen/lein-pprint/classes",
:group "lein-pprint",
:source-path ("/home/phil/src/leiningen/lein-pprint/src"),
:dependencies
([org.clojure/tools.nrepl "0.0.5" :exclusions [org.clojure/clojure]]
[clojure-complete "0.1.4" :exclusions [org.clojure/clojure]]
[org.thnetos/cd-client "0.3.3" :exclusions [org.clojure/clojure]]),
:target-path "/home/phil/src/leiningen/lein-pprint/target",
:name "lein-pprint",
[...]
:description "Pretty-print a representation of the project map."}
In order to prevent profile settings from being propagated to other
projects that depend upon yours, the `:default` profiles are removed
from your project when generating the pom, jar, and uberjar, and an
`:uberjar` profile, if present, is included when creating
uberjars. (This can be useful if you want to specify a `:main`
namespace for uberjar use without triggering AOT during regular
development.) Profiles activated through an explicit `with-profile`
invocation will be preserved.