4

In my Leiningen project.clj I am using environ to set environment variables in different profiles. I want to build a demo uberjar with lein-ring, which uses different values for certain environment variables to the production version. For some reason I cannot seem to pick them up, however.

I have a demo profile defined something like this in my project.clj:

:demo {:dependencies [[javax.servlet/servlet-api "2.5"]]
       :plugins [[lein-environ "0.4.0"]]
       :env {:foo "FOO" :bar "BAR"}}

Then I execute

lein with-profile demo ring uberjar

But accessing foo or bar with environ.core/env inside the resulting standalone jar returns nil in both cases. On the other hand if I run

lein with-profile demo ring server-headless

I can access the values of both.

Why is this happening? It's really not what I would have expected. It looks like the uberjar is always being created with the production profile. Or is something else going?

The lein-ring page does state the following:

Lein-Ring pays attention to several environment variables, including: PORT - the port the web server uses for HTTP SSLPORT - the port the web server uses for HTTPS

These will override any options specified in the project.clj file, but won't override any options specified at the command line.

It's not clear that that means that any other environment variables specified in project.clj will be ignored, however.

Running leiningen 2.3.4 on Windows.

ChrisM
  • 2,128
  • 1
  • 23
  • 41

1 Answers1

3

It looks like that lein-environ plugin isn't actually physically setting environment variables (indeed you can't set environment variables on the current process from within Java - see here for details). Even supposing that it could, ask yourself - how would you ensure that environment variables that were present when building the uberjar are present when it is run?

Rather, lein-environ and the accompanying environ.core/env function provide you a way of faking out environment variables for testing and development purposes, without having to manually set environment variables before launching Leiningen. It does this by writing variables provided in the project map to a .lein-env file from the plugin code, and merging these values with those from the actual operating system environment when calling env from your project code.

So, when you go to run the uberjar, you'll actually need to have these variables present in your Windows environment (or in a .lein-env file in your current directory, which I wouldn't recommend). If your goal is to provide a standalone demo using pre-set environment variables to control certain application behavior, I'd create a .cmd script to distribute with your application that will set the appropriate environment variables and then launch the uberjar.

Community
  • 1
  • 1
Alex
  • 13,811
  • 1
  • 37
  • 50
  • Thanks. Indeed I'm aware how Environ works, but I didn't really get the impression that it was just for testing. I know it says on the website that for production you would substitute in OS environment variables, but I've regarded Environ as something I'd want to use in production, as a nice way of configuring different builds. The idea of setting up these demo vars through a script is an acceptable compromise, I suppose. I could also set them via Java system properties. – ChrisM Mar 13 '14 at 18:53
  • 1
    You could certainly follow a similar approach, writing properties to a resource file that you bundle in the uberjar instead of to the filesystem, but that would require some custom code. However, any code that checks environment variables directly using `System/getenv` would be unaffected by properties set in `lein-environ`. – Alex Mar 13 '14 at 19:34
  • 1
    Also, `environ.core` is perfectly suitable for production use. You just shouldn't expect properties set via `lein-environ` to be visible to your project code except when it's being executed as a Leiningen task. – Alex Mar 13 '14 at 19:38