Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for outputting a subset of the project map #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 14 additions & 7 deletions README.md
Expand Up @@ -32,7 +32,7 @@ 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.
given as its argument.

When configleaf is installed, you can get a list of the currently
active profiles by doing `lein profiles`:
Expand Down Expand Up @@ -152,10 +152,15 @@ key, which should contain a map of option names to their values. Here are the cu
in the `:source-paths` key in the project.
* `:namespace` - Set this key to the name of the namespace, as a
symbol, that you want the project map to be output to. By default,
this has the value `'cfg.current`.
this has the value `cfg.current`.
* `:var` - Set this key to the name of the var, as a symbol, that you
want the project map to be output to. By default, this has the value `project`.
* `:verbose` - Set this key to true if you'd like Configleaf to print
out which profiles are included whenever a task is run. By default,
this key is false.
* `:keyseq` - A keyseq to the subset of the project map you want to output.
By default, the entire project map is used, but you could only output
everything under `:config`, for example, by setting this to `[:config]`.
* `:never-sticky` - When present, 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.
Expand All @@ -164,13 +169,15 @@ So for example, if the project map has the following map in the `:configleaf` ke

```clojure
:configleaf {:config-source-path "src/main/clojure"
:namespace 'myproject.config
: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:
command:

```
David$ lein with-profile test profiles
Expand Down Expand Up @@ -224,7 +231,7 @@ Since all of this extra output is controled by the `:verbose` key in the `:confi
:profiles {:verbose-configleaf {:configleaf {:verbose true}}}
```

Then
Then

```
David$ lein set-profile verbose-configleaf
Expand All @@ -251,7 +258,7 @@ Then add the following key-value pair in the top level of your project map:

```
:hooks [configleaf.hooks]
```
```

That is all you need. But you will probably also want to add two
directories to your `.gitignore` file. The first is the directory
Expand Down Expand Up @@ -289,7 +296,7 @@ add "src/cfg/current.clj" or possibly "src/cfg" to your `.gitignore`, if there a

* Version 0.2.0
* Addition of Java system properties to configurations.
* Changes to configuration map format to allow system properties.
* Changes to configuration map format to allow system properties.

## License

Expand Down
2 changes: 1 addition & 1 deletion project.clj
@@ -1,4 +1,4 @@
(defproject configleaf "0.4.6"
(defproject configleaf "0.4.7"
:description "Persistent and buildable profiles in Leiningen."
:dependencies [[org.clojure/clojure "1.2.0"]
[stencil "0.3.0"]
Expand Down
62 changes: 27 additions & 35 deletions src/configleaf/core.clj
Expand Up @@ -106,6 +106,13 @@
(or (get-in project [:configleaf :namespace])
'cfg.current))

(defn config-var
"Get the var to put the profile info into, or use the default
(which is project)."
[project]
(or (get-in project [:configleaf :var])
'project))

(defn merge-profiles
"Given the project map and a list of profile names, merge the profiles into
the project map and return the result. Will check the :included-profiles
Expand All @@ -126,22 +133,18 @@
{"." "/", "-" "_"})
".clj"))

(defn require-config-namespace
"Put the configured project map (according to given project) into
a var in the config namespace (in the current JVM). Effect is as if
you have 'require'd the namespace, but there is no clj file involved
in the process.

Note the argument is a string. You need to print the project map to a string
to pass it into this function. This is so the string can survive leiningen 2's
own macro handling, which does not prevent a project map from being evaluated,
which you usually can't do, due to symbols and lists that would not eval."
[project-as-str project-metadata-as-str]
(let [project (read-string project-as-str)
project-metadata (read-string project-metadata-as-str)
cl-ns-name (symbol (config-namespace project))]
(create-ns cl-ns-name)
(intern cl-ns-name (with-meta 'project project-metadata) project)))
(defn sub-project
"Return a nested subset of the project map. Also get the same nested subset from each value
in :profiles and put that in the :profiles at the top level. If there is :without-profiles meta on
project, do the same magic for it."
[project keyseq]
(when project
(-> (get-in project keyseq)
(assoc :profiles (into {}
(for [[profile config] (:profiles project)]
[profile (get-in config keyseq)])))
(with-meta (update-in (meta project)
[:without-profiles] sub-project keyseq)))))

(defn output-config-namespace
"Write a Clojure file that will set up the config namespace with the project
Expand All @@ -153,31 +156,20 @@
"src/")
ns-file (io/file src-path
(namespace-to-filepath ns-name))
ns-parent-dir (.getParentFile ns-file)]
ns-parent-dir (.getParentFile ns-file)
config (if-let [keyseq (get-in project [:configleaf :keyseq])]
(sub-project project keyseq)
project)]
(if (not (.exists ns-parent-dir))
(.mkdirs ns-parent-dir))
(spit ns-file
(stencil/render-file
"templates/configleafns"
{:namespace ns-name
:project project
:project-metadata (select-keys (meta project)
[:without-profiles
:included-profiles])}))))

(defn set-system-properties
"Given a map of string keys to string values, sets the Java properties named
by the keys to have the value in the corresponding value."
[properties]
(let [props (Properties. (System/getProperties))]
(doseq [[k v] properties]
(try
(.setProperty props k v)
(catch Exception e
(println "Configleaf")
(println " Java property keys and values must both be strings.")
(println (str " Skipping key: " k " value: " v)))))
(System/setProperties props)))
:var (config-var project)
:config config
:config-metadata (select-keys (meta config)
[:without-profiles :included-profiles])}))))

(defn check-gitignore
"Check the .gitignore file for the project to see if .configleaf/ is ignored,
Expand Down
4 changes: 2 additions & 2 deletions src/templates/configleafns.mustache
Expand Up @@ -7,7 +7,7 @@

(ns {{&namespace}})

(def project '{{&project}})
(def {{&var}} '{{&config}})

{{! Easiest to just alter-var-root the project var with metadata. }}
(alter-var-root #'project with-meta '{{&project-metadata}})
(alter-var-root #'{{&var}} with-meta '{{&config-metadata}})