Spin off separate profile guide from readme/tutorial.

This commit is contained in:
Phil Hagelberg 2012-05-24 18:26:46 -07:00
parent 9a5dba9a37
commit dff9a6cf24
8 changed files with 146 additions and 156 deletions

View file

@ -54,11 +54,9 @@ project, but here are the commonly-used tasks:
$ lein repl # launch an interactive REPL session
$ lein jar # package up the whole project as a .jar file
$ lein run -m my.namespace # run the -main function of a namespace
$ lein install # install a project into the local repository
$ lein search [TERM] # find jars for your project.clj dependencies
$ lein uberjar # package the project and dependencies as standalone jar
Use `lein help` to see a complete list. `lein help $TASK` shows the
usage for a specific task.
@ -71,7 +69,7 @@ Most tasks need to be run from somewhere inside a project directory to
work, but some (`new`, `help`, `search`, `version`, and `repl`) may
run from anywhere.
See the [FAQ](https://github.com/technomancy/leiningen/blob/preview/doc/FAQ.md)
See the [FAQ](https://github.com/technomancy/leiningen/blob/master/doc/FAQ.md)
for more details.
## Configuration
@ -82,103 +80,20 @@ The `project.clj` file in the project root should look like this:
(defproject myproject "0.5.0-SNAPSHOT"
:description "A project for doing things."
:url "http://github.com/technomancy/myproject"
:dependencies [[org.clojure/clojure "1.2.1"]]
:dependencies [[org.clojure/clojure "1.4.0"]]
:plugins [[lein-ring "0.4.5"]])
```
To find specific versions of a dependency, use `lein search`, though
note that this can be extremely slow the first time you use it.
The `lein new` task generates a project skeleton with an appropriate
starting point from which you can work. See the
[sample.project.clj](https://github.com/technomancy/leiningen/blob/preview/sample.project.clj)
file (also available via `lein help sample`) for a detailed listing of
configuration options.
### Profiles
The `project.clj` file can be customized further with the use of
[profiles](https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md).
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 Swank
Clojure available in every project you hack on without modifying every
single project.clj you use.
By default the `:dev`, `:user`, and `:default` profiles are activated
for each task, but the settings they provide are not propagated
downstream to projects that depend upon yours. Each profile is defined
as a map which gets merged into your project map. To add resources
directories during development, add a `:profiles` key to project.clj
like so:
```clj
(defproject myproject "0.5.0-SNAPSHOT"
:description "A project for doing things."
:dependencies [[org.clojure/clojure "1.2.1"]]
:profiles {:dev {:resources-path ["dummy-data"]}})
```
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. In addition to `project.clj`, profiles specified in
`~/.lein/profiles.clj` will be available in all projects, though those
from `profiles.clj` will be overridden by profiles of the same name in
the `project.clj` file. This is why 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 `profiles.clj` define a `:dev` profile.
If you want to access dependencies during development time for any
project place them in your `:user` profile.
```clj
{:user {:plugins [[lein-swank "1.4.0"]
[lein-pprint "1.1.1"]]}}
```
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"]]}})
```
To activate other profiles for a given run, 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
A single `with-profile` call does not apply across task comma-chains.
To see how a given profile affects your project map, use the
[lein-pprint](https://github.com/technomancy/leiningen/tree/master/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."}
### Leiningen Plugins
## Plugins
Leiningen supports plugins which may contain both new tasks and hooks
that modify behaivour of existing tasks. See

121
doc/PROFILES.md Normal file
View file

@ -0,0 +1,121 @@
# 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 Swank
Clojure available in every project you hack on without modifying every
single project.clj you use.
By default the `:dev`, `:user`, and `:default` profiles are activated
for each task, but the settings they provide are not propagated
downstream to projects that depend upon yours. Each profile is defined
as a map which gets merged into your project map.
The example below adds a "dummy-data" resources directory during
development and a dependency upon "midje" 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 {:resources-path ["dummy-data"]
:dependencies [[midje "1.4.0"]]}})
```
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.
## Declaring Profiles
In addition to `project.clj`, profiles specified in
`~/.lein/profiles.clj` will be available in all projects, though those
from `profiles.clj` will be overridden by profiles of the same name in
the `project.clj` file. This is why 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 `profiles.clj` define a `:dev` profile.
Use the `show-profiles` task to see what's available.
If you want to access dependencies during development time for any
project place them in your `:user` profile.
```clj
{:user {:plugins [[lein-swank "1.4.0"]
[lein-pprint "1.1.1"]]}}
```
Profiles are merged by taking each key and combining the value if it's
a collection and replacing it if it's not. Profiles specified earlier
take precedence when replacing. 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 or be
displaced 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.
## Activating Profiles
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"]]}})
```
To activate other profiles for a given run, 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
A single `with-profile` call does not apply across task comma-chained tasks.
## Debugging
To see how a given profile affects your project map, use the
[lein-pprint](https://github.com/technomancy/leiningen/tree/master/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. Profiles
activated through an explicit `with-profile` invocation will be
preserved. The `repl` task uses its own profile in order to inject
dependencies needed for the repl to function.

View file

@ -78,21 +78,6 @@ They usually contain .class files (JVM bytecode) and .clj source
files, but they can also contain other things like config
files.
<!--
TODO: bring back this section if we can speed up search
The `lein search` command will search each remote repository:
$ lein search lancet
== Results from clojars - Showing page 1 / 1 total
[lancet "1.0.0"] Dependency-based builds, Clojure Style.
[lancet "1.0.1"] Dependency-based builds, Clojure Style.
Note that this command will take many minutes to run the first time
you invoke it on a given machine; it needs to download a rather large
index.
-->
You can [search Clojars](http://clojars.org/search?q=clj-http) using its
web interface.
@ -101,9 +86,9 @@ web interface.
This shows two different ways of specifying a dependency on the latest
stable version of the `clj-http` library, one in Leiningen format and
one in Maven format. We'll skip the Maven one for now, though you'll
need to learn to read it for Java libraries. You can copy the
Leiningen version directly into the `:dependencies` vector in
`project.clj`.
need to learn to read it for Java libraries from
[Central](http://search.maven.org). You can copy the Leiningen version
directly into the `:dependencies` vector in `project.clj`.
Within the vector, "clj-http" is referred to as the "artifact id".
"0.4.1" is the version. Some libraries will also have "group ids",
@ -144,44 +129,6 @@ in project.clj. See the
TODO: cover repl, run, trampoline tasks
<!-- TODO: move this section
## Profiles
Sometimes you want to pull in dependencies that are really only
necessary while developing; they aren't required for the project to
function in production. You can do this by adding a `:dependencies`
entry to the `:dev` profile. These will be available unless you
specify different profiles using the `with-profiles` task, but they
are not brought along when another project depends on your project.
Using [midje](https://github.com/marick/Midje) for your tests would be
a typical example; you would not want it included in production, but it's
needed to run the tests:
```clj
(defproject my-stuff "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.3.0"]]
:profiles {:dev {:dependencies [[midje "1.3.1"]]}})
```
Note that profile-specific dependencies are different from plugins in
context; plugins run in Leiningen's process while dependencies run in
your project itself. (Older versions of Leiningen lacked this distinction.)
If you have dependencies that are not _necessary_ for developing but
just for convenience (things like
[Swank Clojure](http://github.com/technomancy/swank-clojure) for Emacs
support or [clj-stacktrace](http://github.com/mmcgrana/clj-stacktrace)
you should add them to the `:user` profile in `~/.lein/profiles`
instead of the `:dev` profile. Both those profiles are active by
default; the difference is the convention for where they are specified.
-->
## Tests
It's easy to kick off a test run:
@ -345,8 +292,8 @@ a public repository. While it's possible to
[maintain your own private repository](https://github.com/technomancy/leiningen/blob/preview/doc/DEPLOY.md)
or get it into Central, the easiest way is to publish it at
[Clojars](http://clojars.org). Once you have
[created an account](https://clojars.org/register) there, publishing
is easy:
[created an account](https://clojars.org/register) there with your SSH
public key, publishing is easy:
$ lein jar, pom
$ scp pom.xml target/my-stuff-0.1.0.jar clojars@clojars.org:

View file

@ -0,0 +1 @@
../../../doc/PROFILES.md

View file

@ -53,6 +53,7 @@
;; looked up in ~/.lein/profiles.clj rather than set in project.clj.
;; Use the with-profiles higher-order task to run a task with a
;; different set of active profiles.
;; See `lein help profiles` for a detailed explanation.
:profiles {:dev {:resource-paths ["dummy-data"]
:dependencies [[clj-stacktrace "0.2.4"]]}
:debug {:debug true

View file

@ -92,7 +92,8 @@
(defn ^:no-project-needed help
"Display a list of tasks or help for a given task.
Also provides readme, faq, tutorial, news, sample, deploying and copying info."
Also provides readme, faq, tutorial, news, sample, profiles,
deploying and copying info."
([project task] (println (or (static-help task) (help-for project task))))
([project]
(println "Leiningen is a tool for working with Clojure projects.\n")
@ -105,4 +106,5 @@ Also provides readme, faq, tutorial, news, sample, deploying and copying info."
(println "\nAliases:")
(doseq [[k v] aliases]
(println (str k " " v)))))
(println "\nSee also: readme, faq, tutorial, news, sample, deploying and copying.")))
(println "\nSee also: readme, faq, tutorial, news, sample, profiles,
deploying and copying.")))

View file

@ -1,15 +1,15 @@
(ns leiningen.profiles
(ns leiningen.show-profiles
(:require [clojure.string]
[clojure.pprint :as pprint]
[leiningen.core.project :as project]
[leiningen.core.user :as user]))
(defn- all-profiles [project]
(merge (deref project/default-profiles)
(merge @project/default-profiles
(user/profiles)
(:profiles project)))
(defn ^:no-project-needed profiles
(defn ^:no-project-needed show-profiles
"List all available profiles or display one if given an argument."
([project]
(->> (all-profiles project)

View file

@ -13,7 +13,10 @@
"Apply the given task with the profile(s) specified.
Comma-separated profiles may be given to merge profiles and perform the task.
Colon-separated profiles may be given for sequential profile task application."
Colon-separated profiles may be given for sequential profile task application.
To list all profiles or show a single one, see the show-profiles task.
For a detailed description of profiles, see `lein help profiles`."
[project profiles task-name & args]
(let [profile-groups (seq (.split profiles ":"))
project (:without-profiles (meta project) project)