Can't access environment variables in leiningen project.clj with environ - clojure

I am trying to use environ to access environment variables specified in my project.clj :dev profile. This looks like a nice way to set up different configuration options, but I can't seem to get it to work. My project.clj entry looks like this:
:profiles
{:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
[ring-mock "0.1.5"]]
:env {:foo "FOO" :bar "BAR"}}}
If I run lein repl and require then enter (with in-ns) a namespace from my project, environ.core/env just returns nil:
(environ.core/env :foo)
nil
Adding an :env entry to the :user profile in .lein/profiles.clj also doesn't work. What am I doing wrong?

OK, it was a case of reading the docs more thoroughly. :) To access environment variables specified in the project map you need the lein-environ plugin. Add it like this:
:plugins [[lein-environ "0.4.0"]]
That worked. It's easy to miss that in the docs though.

Related

Distributing a simple library via clojars

I have implemented a hyphenation algorithm (at namespace hyphenator-clj.core), defined it as org.clojars.nikonyrh.hyphenator-clj 0.1.0 at defproject and pushed it to Clojars. Uberjar seems to have files like core__init.class, core.clj and core.class.
However when I try to use it as a dependency on an other project I get this error:
$ lein uberjar
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.pom from clojars
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.jar from clojars
Compiling example.core
java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
...
Must I change my project's folder structure so that it matches the expected org/clojars/nikonyrh/hyphenator_clj__init.class, or can I somehow override the current behavior? If there is a good tutorial about this out there I would be happy to read it.
Basically I would like to get this example project to work. project.clj:
(defproject example "0.0.1-SNAPSHOT"
:description ""
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojars.nikonyrh.hyphenator-clj "0.1.0"]]
:javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
:aot [example.core]
:main example.core)
src/example/core.clj:
(ns example.core
(:require [org.clojars.nikonyrh.hyphenator-clj :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
I'm suspecting I also have the english.txt in a wrong directory, as it isn't contained in the uberjar but resource files are an other topic.
You would probably be better off not using a hyphen in the namespace hyphenator-clj. Why not just use hyphenator? But if you do I suspect that the name of the directory should have an underscore in it rather than a hyphen, so be: hyphenator_clj.
If fixing that issue doesn't help then another thing to look out for, which I can't see from your question, is where exactly is core.clj in the directory structure, and does the project.clj reflect that? For instance is the path for the namespace hyphenator-clj.core in a src directory off the root of your project? The root of your project being defined as where the project.clj is located.
Something else that would be good to see in the question is whether you can get the program to work just locally, without having packed it up into an uberjar and shipped it to clojars. My guess would be that it does work locally, but it would help for that to be stated.
Okay taking a look at your links now. You might like to read a working project deployed to clojars, that has hypens in its name, for instance here. The first difference you might notice is the project name you use is rather long: org.clojars.nikonyrh.hyphenator-clj. It should just be hyphenator-clj. Also I would recommend having an identifier ending in "-SNAPSHOT" as that project does.
But taking a look at the bigger picture, a great idea you suggested in the comments is to test without Clojars being in the mix at all. To do this use lein install on the library you want to use from another lein project.
Ahaa at least I understand the process a bit better now, basically my require has to match the structure of the used JAR file, which may be very different from the project's name. For example cc.qbits/spandex is actually required as qbits.spandex.
The english.txt dependency was fixed by moving it to resources folder, deploying the new version to Clojars and importing the dependency as it exists in the JAR:
(ns example.core
(:require [hyphenator-clj.core :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))

How i can add github/local dependencies with Boot (clojure)

For instance i want to fork some existing clojar, extend it and use in my project.
How i can do this w/o pushing to clojars/maven?
Interested in both options: link to github and local path.
Thanks!
UPD
What i want is to include some existing Clojure project as dependency, similar like ruby gem allows.
Is this possible with Boot? Or i always need to compile to java?
Here is how I have setup my fork of castra on the castra-simple example for hoplon.
https://github.com/hoplon/demos/tree/master/castra-simple
open shell
git clone castra:repo
in castra dir
file: build.boot
; ...
(def +version+ "3.0.0-SNAPSHOT")
; ...
boot watch build-jar
open new shell
git clone castra-simple:repo
in castra-simple
file: boot.build
(set-env!
:dependencies
'[
;; ...
[hoplon/castra "3.0.0-SNAPSHOT"] ;;forked repo
;; ...
]
:source-paths #{"src"}
:resource-paths #{"assets"})
;; ...
(deftask dev
"Build castra-simple for local development."
[]
(comp
(serve
:handler 'app.handler/app
:reload true
:port 8000)
(watch) (speak) (hoplon) (reload) (cljs-repl) (cljs)
;;forked repo
(checkout :dependencies '[[hoplon/castra "3.0.0-SNAPSHOT"]])))
boot dev
As i figured out with Boot you can specify source-paths:
(set-env! :source-paths #{"src", "../clj-mailgun/src"})
This is the only way to add other projects into your. (adding source-code, not .jar)
There is no way to specify github link - you should clone it manually and add to :source-paths path.
Please correct me if i am missing something.

lein repl starts in wrong namespace

TLDR;
lein repl starts in the namespace defined by :main in project.clj, instead of user, as desired.
Details
I have a Leiningen project which is deployed as a command-line application in an uberjar, so I can run it like so:
java -jar my-app-1.0-standalone.jar --some --args
I also have a dev/user.clj to give me a nice REPL environment, as described here.
My project.clj looks like this:
(defproject my-app "1.0"
:main my-app.cli
:aot [my-app.cli]
:profiles {:dev {:source-paths ["src" "dev"]}})
When I start my REPL, either with lein repl from the command line or M-x cider-jack-in from Emacs, I am in the my-app.cli namespace, rather than user.
If I remove :main my-app.cli from project.clj, my REPL starts in the user namespace as I'd expect, but clearly this breaks my uberjar.
Any ideas?
When lein repl task runs, it will look up the ns to switch to in this order of preference:
ns specified in the :init-ns of the :repl-options
ns specified :main
user ns
In your case, try adding:
:repl-options {:init-ns user}
to your project.clj

leinigen repl with profile

This question is a follow up to How does one pre-load a clojure file in the leiningen repl?.
My ~/.lein/profiles.clj looks as follows:
{
:user {:source-paths ["C:/Users/username/.lein/src"] }
}
My ~/.lein/src/user.clj might look as follows:
(ns user)
(println "user file loaded")
When I run lein repl within a folder containing a project.clj, then the user.clj file is executed, but when I run lein repl from another folder it doesn't load my user profile. Is there a workaround for this or is this behavior by design? In fact, I know that Leinigen is indeed loading my profile.clj (even when there is no project.clj) because there are also other things inside (taken from the excellent pimp my repl article). Leinigen is just having problems with my additional source-paths setting.
One other question related to this is the fact that I need to specify the full path of the folder for my user.clj file : "C:/Users/username/.lein/src". When I change that to "~/.lein/src" leiningen fails to load my file.
It sounds like you just want some code loaded for your lein repl sessions. This is done with the :init key of the :repl-options in your profiles.clj. You can load-file other files in init if you want to organize in that fashion.
{:user
{:repl-options
{:init (load-file "path-to-file/user.clj")}
...}}
Note: If you are using Windows-style path delimiters /, you'll need to escape them //.

How do I get Clojure to load a project-specific .clj file on REPL launch?

How do I get Clojure to load a project-specific .clj file on repl launch? I want to have some function available to me whenever I open up a new repl (I'm using nREPL on emacs, for what it's worth...)
Thanks
Add an entry to your project.clj's :repl-options like the following
:repl-options {:init (load-file "src/your-project-specific-file.clj") }
If you'd like your functions to be available in all your REPLs, add an entry the user profile in .lein/profiles.clj as follows:
{
:user
{:repl-options {:init (load-file "path/to/file.clj")}}
}