Pass argument to leiningen readable by project.clj - clojure

I have a project.clj file that I want to use differently depending on an argument passed in when called by leiningen. Here is my hypothetical sample project
(defproject simple "0.0.1"
:source-paths [(get-argument "source.path")])
(In this case get-argument would simply call System/getProperty). I would use this file like this,
lein2 compile -Dsource.path=path/to/location
The problem is two-fold,
I don't know how to pass an argument to leiningen. It doesn't accept the -Dkey=value syntax. I couldn't find anything in documentation about passing optional/extra arguments. Am I missing something obvious?
The subforms inside defproject seem to be handled a special way. I couldn't find an easy way to put code into it.
I have found some approaches
https://github.com/weavejester/environ looks promising, but it seems to work only in proper clojure code, not inside project.clj
https://groups.google.com/forum/?fromgroups=#!topic/leiningen/t8G6Et1_j8w -- this is a workaround that may solve half of the problem
What is an elegant way to set up a leiningen project that requires different dependencies based on the build platform? gives some idea how to eval code in project.clj
https://github.com/sattvik/leinjacker promises to do some dirty tricks, but I couldn't make it work in my environment
(What I actually want to use it for is that I have a clojurescript project with different artifacts. While it's possible to configure different builds for it, they all share the same crossovers.)

One approach that is convenient on unix-like platforms is to use an environment variable, combined with lein's willingness to evaluate expressions marked with a tilde in project.clj files. So for your example, you could provide a project.clj like:
(defproject simple "0.0.1"
:source-paths [~(System/getenv "MY_SRC_PATH")]
:dependencies [[org.clojure/clojure "1.5.0"]])
...then set the environment variable when launching lein like this:
MY_SRC_PATH="s2" lein compile
I don't know how well this approach would work on Windows.

Related

How to run library's `main` with Leiningen?

I had used some library, let's say it is Clojure itself (which is always added to project.clj). Clojure provides clj CLI tool (which is src/cli/clojure/main.clj, but nevermind). How to use it with lein? I mean, is there any command/plugin/technique which will allow me to use library's main?
Every Var in every namespace is equal in the eyes of Clojure. From your code, just execute like:
(some.awesome.lib/-main ...)
or whatever the fully-qualified symbol pointing to the Var in question.
For further details, please see this question:
When to use a Var instead of a function?
Also
See the output of
> lein help run
Using lein, you can type
lein run -m my.awesome.proj/some-fn
or
lein run -m some.awesome.lib/-main
since to Clojure some.awesome.lib/-main is no different than any other function (the hyphen prefix on -main is just a convention and makes no difference to the Clojure compiler).
You can also set up project.clj to automatically call any function of your choosing when you type lein run by adding:
:main some.awesome.lib/-main

Dealing with resources (copying) when building a ClojurScript project using leiningen

I have just begun playing with ClojureScript and I'd like to collect all CSS files into a single folder (out/css). I found leiningen-less and with the following config I get the compiled CSS files into the correct location:
:less {:source-paths ["src/less"]
:target-path "out/css"}
I can't find any documentation on how I can handle the ordinary CSS files (e.g. the file for resetting defaults, css/reset.css). Basically I want the equivalent of cp css/*css out/css.
I did find lein-resource but it does a bit more than I require (pass things through stencil) and more importantly it through an UnsupportedOperationException on my with what I thought would a be a valid configuration:
:resource {:resource-paths ["css" {:target-path "out/css"}]}
Please englighten me!
For your particular use case just rename reset.css to reset.less. less should be able to read CSS without problems.
For more advanced frontend tooling maybe consider adding something like make/grunt/etc. More complexity but more power & flexibility.
I think better and easy solution would be that you write a function that uses clojure.java.io library functions and integrate them with lein-less "compiler" fork, so this is my internal function proposal:
(defn your-fn[]
(remove-folder "./out") ;; => you have to do how to make that fn following io lib doc
(copy-folder "./css ./out") ;; ;; => you have to do how to make that fn following io lib doc
(run-compiler :javascript
{:project-root "your-project-root/"
:source-paths ["less"]
:target-path "out"})))
PS: note that you need to call this fn from your clojurescript compilation process, BTW I didn't know if there is a way for that :)

Trying to understand implicit Leiningen source path/namespace set up assumptions

(Sorry this is so long. It's long to rule out misunderstandings, not because I want you to figure out what my question should be.)
I understand the basics of Clojure namespaces, and that the namespaces listed in my ns statements at the beginnings of files have to match locations of files in a directory hierarchy. I have figured out part of what Leiningen is doing automatically to set up search load, and part of what it is loading automatically, but ... it's still driving me crazy. The problem is that there are things that Leiningen seems to set up implicitly, that are also not well documented in the obvious places like the Leiningen tutorial and the sample project file. (Maybe the information is there, but I haven't found it/interpreted it.)
I've got things set up so that when I do lein repl, the main source files are loaded (popco.clj and acme.clj below), but loading other files causes trouble. I want to make the MWE as minimal possible, and the question short, but I want to make it clear that I am not asking simpler questions that have been answered already (e.g. this one).
Here's where source files are, with ns statements from the same files listed over on the right:
src/popco/sims/sim1/sim1propns.clj (ns popco.sims.sim1.sim1propns)
src/utils/general.clj (ns utils.general)
src/popco/core/acme.clj (ns popco.core.acme)
src/popco/core/popco.clj (ns popco.core.popco
[:use popco.core.acme]
[:import [popco.core.acme Propn Obj]]
(:gen-class)) ; not sure what this does yet
Here's the project.clj file:
(defproject popco-x "0.0.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.5.1"]]
:main popco.core.popco
:profiles {:dev {:dependencies []
:source-paths ["src"] }})
When I run lein repl, I see that I'm in the popco.core.popco namespace:
popco.core.popco=>
and I find that both functions and record types defined in acme.clj are available. I have learned (by trial and error) that ":main popco.core.popco" in project.clj is causing popco.clj to run, and that results in the the REPL being left in the popco.core.popco namespace. So far, so good.
Here are my questions:
What if I want to load src/utils/general.clj, or src/popco/sims/sim1/sim1propns.clj ? I can load them with load-file, but I'd like to use load in the REPL, and more importantly, I'd like to be able to require or use these source files from other source files. How can I reference the functions in general.clj from inside acme.clj, for example? I think the answer might be to add entries to the sequence after :source-paths in project.clj, but I'm confused about what should go there.
Feel free to recommend anything. Other directory structures, radical changes to project.clj, whatever.
Everything about your project structure and project.clj looks entirely normal.
What if I want to load src/utils/general.clj:
This is almost always done through a require or use expression. While it is possible to load a file with load-file this requires you to specify the path (relative to where you started the JVM) to the file. load loads it relative to the class-path though in practice these are almost never used when the files being loaded are part of the project. In that case you can simply require them.
I'd like to be able to require or use these source files from other source files:
The expected way of doing this is to put a (:require [popco.core.acme :as acme]) statement in the ns form at the top of the namespace that wants to use functions from that namespace.
How can I reference the functions in general.clj from inside acme.clj:
(ns popco.core.acme
(:require [utils.general :refer [function1 function2] :as general))
I think the answer might be to add entries to the sequence after :source-paths in project.clj:
You will most likely never need to put anything there. require and use are the appropriate tool for this. They will already be able to find all the files under /src/ because those files will be in the classpath when the leiningen starts java. You can see the class path used with the lein classpath function.
ps: You can also call require and use as functions (form the REPL for instance), though doing this in the ns form is generally preferred.

What is the easiest way to load a clojure library all the time?

A question from an utter newcomer to clojure: What if I want to be able to start a clojure REPL from anywhere, for example because I just want to compute an exponent? How can I set up my system to do this? (I've deleted earlier links to not-quite-answers because they were cluttering up the question.) The Pomegranate documentation linked by #Jared314's answer below helped me see that I can do this:
~$ lein repl
...
user=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
user=> (add-dependencies :coordinates '[[org.clojure/math.numeric-tower "0.0.2"]])
{[org.clojure/clojure "1.3.0"] nil, [org.clojure/math.numeric-tower "0.0.2"] #{[org.clojure/clojure "1.3.0"]}}
user=> (use 'clojure.math.numeric-tower)
nil
user=> (expt 2 3)
8
Yay!
Now how can I make this happen every time I start the REPL, no matter what subdirectory I'm in?
I think I'm just ignorant of basic clojure setup. Sorry about that.
Second major edit:
I've figured out that if I use raw clojure without lein, I can execute commands on startup of the repl. For example, if the file .clojurerc contains the text (print "Yow!\n"), I can do this:
~$ java -cp /usr/local/lib/clojure-1.5.1/clojure-1.5.1.jar clojure.main -i .clojurerc -r
Clojure 1.5.1
Yow!
user=>
Can I do something like this with lein? Or maybe better yet, load clojure.math.numeric-tower automatically in clojure without using lein (since for simple command line experimentation, lein's startup is slower than starting clojure directly).
(It may seem as if I'm not trying to solve this on my own, but I that's not so. I have been doing web searches and experimenting, but I keep hitting brick walls. I'm starting to feel as if clojure is only intended for full-blown programming projects. I had assumed that it could be good for add-hoc experiments and calculations (as lisps traditionally are but Java is not). I'm not trying to incite arguments. I'm just frustrated. There ought to be a simple, well-known formula for doing what I'm trying to do.)
When you want external dependencies you will need either a new project, lein new testproject1, the lein-oneoff plugin, Pomegranate, a Leiningen profile :dependencies entry, or some specific IDE feature. (I know at least LightTable allows external dependencies in their Instarepl, so I assume you can do it in Emacs and CCW.)
It might be best to start with creating a new test project so you can see the project.clj layout. But, if you just want a one-off library in a repl, take a look at the instructions for Pomegranate's add-classpath command. Pomegranate is accessible by default in the lein repl, so their example should work without anything extra.
Edit:
From your updated question, it sounds like you want a persistent repl dependency. You can add [org.clojure/math.numeric-tower "0.0.2"] to your ~/.lein/profiles.clj profile file, under the :repl profile.
{:user {}
:repl {:dependencies [[org.clojure/math.numeric-tower "0.0.2"]]
:repl-options {:init (use 'clojure.math.numeric-tower)}}}
Then when you run lein repl:
(expt 2 3) ;=> 8
Looking at this question a few months later, I realized that I settled on a different solution, but never posted it. I now leave references to math.numeric-tower out of both .clojurerc and .lein/project.clj, since I don't need it for most Leiningen projects. And when I want to use Clojure for quick calculations, I start Clojure via a shell script without Leiningen to avoid slow startup. This is what's in the shell script:
#!/bin/sh
jars=/usr/local/lib/clojure-1.5.1/clojure-1.5.1.jar:/usr/local/lib/clojure-1.5.1/math.numeric-tower-0.0.2.jar
while [ "$1" != "${1%.jar}" ]; do # while param is a jar file
jars="$jars:$1"
shift
done
jars="$jars:."
exec rlwrap java -cp "$jars" clojure.main -e "(use 'clojure.math.numeric-tower)" "$#" -r
The middle part allows you to add jars on the command line, but in practice I don't find that useful, given that I use Leiningen for ongoing projects. Someone else might find that part of the script useful, though. rlwrap is a utility that gives you command line history, though it's not as good as what Leiningen provides, for my purposes.

FileNotFoundException when making a jar file from the clojure file

I am trying to go through the process of creating a jar file from a simple clojure file. Below is my clojure code:
(ns app.first (:gen-class))
(refer 'clojure.core)
(defn -main [& args] (println "this program worked!"))
I am using these instructions to create the jar file: http://en.wikibooks.org/wiki/Clojure_Programming/Tutorials_and_Tips
I see the error "java.io.FileNotFoundException: Could not locate app/hello__init.class or app/hello.clj on classpath: (NO_SOURCE_FILE:0)" when I try to complete the (compile 'app.first) step.
The only difference between my attempt and the link is the name of my file (first.clj instead of hello.clj).
Can anyone see where I am going wrong? Or for that matter, all I want to do is learn how to create a jar from a clojure file, so if anyone knows of a better/easier way to do that, let me know.
It's better to use Leiningen for such tasks - it allows to maintain dependencies, and packs all necessary components into jar file
I'm rusty on this, but I heard about other people with similar problems.
I think it's helpful to remember that the classpath you indicate points to the root of your class tree, and package names end up creating subdirectories within that tree. Awkwardly stated, but I hope you get the idea. Thus, I think you need to do some kind of gymnastics with creating directories to match the "app.first" -> "/app/first" hierarchy.
Sorry, that's as close as I come to a sensible and useful answer. Hope this helps you.
EDIT:
The Prime Directive of Computer Science: It only works if you do everything right! I spent almost 10 minutes fiddling with this but was finally successful.
Here's what I needed to do to get your program to compile:
created a directory app, and within that, first.clj with your code.
checked for the *compile-path* by doing (pr *compile-path) within Clojure. It said "classes".
created a second directory classes parallel to app.
in the shell, did export CLASSPATH=.:./classes
in Clojure, did (compile 'app.first)
... and I found a bunch of class files in classes. JARring those should be a snap.
I found it very helpful to run (doc compile) because that reminded me of the requirement to have a directory to satisfy the requirement for a *compile-path*.